ويكاموس
arwiktionary
https://ar.wiktionary.org/wiki/%D9%88%D9%8A%D9%83%D8%A7%D9%85%D9%88%D8%B3:%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9
MediaWiki 1.47.0-wmf.2
case-sensitive
ميديا
خاص
نقاش
مستخدم
نقاش المستخدم
ويكاموس
نقاش ويكاموس
ملف
نقاش الملف
ميدياويكي
نقاش ميدياويكي
قالب
نقاش القالب
مساعدة
نقاش المساعدة
تصنيف
نقاش التصنيف
ملحق
نقاش الملحق
مكنز
نقاش المكنز
TimedText
TimedText talk
وحدة
نقاش الوحدة
فعالية
نقاش فعالية
ويكاموس:GUS2Wiki
4
216488
1090025
1089955
2026-05-16T11:41:18Z
Alexis Jazz
28437
Updating gadget usage statistics from [[Special:GadgetUsage]] ([[phab:T121049]])
1090025
wikitext
text/x-wiki
{{#ifexist:Project:GUS2Wiki/top|{{/top}}|This page provides a historical record of [[Special:GadgetUsage]] through its page history. To get the data in CSV format, see wikitext. To customize this message or add categories, create [[/top]].}}
البيانات التالية مخزنة، وكان آخر تحديث لها في 2026-05-16T05:08:40Z. العدد الأقصى للنتائج المخزنة هو {{PLURAL:5000||نتيجة واحدة|نتيجتان|5000 نتائج|5000 نتيجة}}.
{| class="sortable wikitable"
! الإضافة !! data-sort-type="number" | عدد المستخدمين !! data-sort-type="number" | مستخدمين نشطين
|-
|AjaxEdit || 30 || 0
|-
|BiDiEditing || 72 || 1
|-
|Cat-a-lot || 10 || 0
|-
|HotCat || 87 || 5
|-
|JSL || 14 || 1
|-
|Linkscount || 18 || 0
|-
|MobileCategories || 14 || 1
|-
|Numeral converter || 1 || 0
|-
|Numeral-converter-toggle || 5 || 1
|-
|ShortLink || 60 || 1
|-
|UTCLiveClock || 84 || 0
|-
|VE-wditem-input-loader || 11 || 2
|-
|XTools-ArticleInfo || 2 || 0
|-
|auto-cite-wikidata-loader || data-sort-value="Infinity" | افتراضي || data-sort-value="Infinity" | افتراضي
|-
|autocomplete || 27 || 0
|-
|mobile-sidebar || 2 || 0
|-
|newsectionbottom || 11 || 0
|-
|searchlang || 22 || 0
|-
|speed-deletion || 6 || 1
|-
|userinfo-without-deletedcontribs || 22 || 1
|-
|wikEd || 44 || 1
|}
* [[خاص:GadgetUsage]]
* [[m:Meta:GUS2Wiki/Script|GUS2Wiki]]
<!-- data in CSV format:
AjaxEdit,30,0
BiDiEditing,72,1
Cat-a-lot,10,0
HotCat,87,5
JSL,14,1
Linkscount,18,0
MobileCategories,14,1
Numeral converter,1,0
Numeral-converter-toggle,5,1
ShortLink,60,1
UTCLiveClock,84,0
VE-wditem-input-loader,11,2
XTools-ArticleInfo,2,0
auto-cite-wikidata-loader,default,default
autocomplete,27,0
mobile-sidebar,2,0
newsectionbottom,11,0
searchlang,22,0
speed-deletion,6,1
userinfo-without-deletedcontribs,22,1
wikEd,44,1
-->
ezdav33b0bzjlj0aof8u8hp5yues258
وحدة:معجمية ويكي بيانات
828
236469
1090001
1075653
2026-05-15T17:15:57Z
Mdktb
25941
إزالة مسافات زائدة بين المراجع؛ تجاهل إضافة مسافة قبل علامات الاستبدال التي تبدأ بـ \127 (يولدها ميدياويكي لحماية المراجع أثناء الـ Parsing)
1090001
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Inline i18n configuration for Arabic
local i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
-- Inline getArgs replacement
local function getArgs(frame)
local args = {}
local parent_args = frame:getParent() and frame:getParent().args or {}
-- Merge frame.args and parent_args
for k, v in pairs(frame.args) do
if v ~= '' then args[k] = v end
end
for k, v in pairs(parent_args) do
if v ~= '' and args[k] == nil then args[k] = v end
end
return args
end
base_lang_code_labels = 'ar' -- Item labels/descriptions/aliases, sense descriptions
base_lang_code_forms = 'ar' -- Lexeme lemmas, form spellings
base_lang_wiki = 'arwiki' -- Wikipedia link
formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = True })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
rcmlye0wratxuauhtjiw53ogkr9kzf7
1090002
1090001
2026-05-15T17:46:55Z
Mdktb
25941
تصويب
1090002
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Inline i18n configuration for Arabic
local i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
-- Inline getArgs replacement
local function getArgs(frame)
local args = {}
local parent_args = frame:getParent() and frame:getParent().args or {}
-- Merge frame.args and parent_args
for k, v in pairs(frame.args) do
if v ~= '' then args[k] = v end
end
for k, v in pairs(parent_args) do
if v ~= '' and args[k] == nil then args[k] = v end
end
return args
end
base_lang_code_labels = 'ar' -- Item labels/descriptions/aliases, sense descriptions
base_lang_code_forms = 'ar' -- Lexeme lemmas, form spellings
base_lang_wiki = 'arwiki' -- Wikipedia link
formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
4apxlu95b36kuiqvxbp29bvnt5v60zi
1090003
1090002
2026-05-15T18:15:57Z
Mdktb
25941
دوال يفترض أن تكون local
1090003
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Inline i18n configuration for Arabic
local i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
-- Inline getArgs replacement
local function getArgs(frame)
local args = {}
local parent_args = frame:getParent() and frame:getParent().args or {}
-- Merge frame.args and parent_args
for k, v in pairs(frame.args) do
if v ~= '' then args[k] = v end
end
for k, v in pairs(parent_args) do
if v ~= '' and args[k] == nil then args[k] = v end
end
return args
end
base_lang_code_labels = 'ar' -- Item labels/descriptions/aliases, sense descriptions
base_lang_code_forms = 'ar' -- Lexeme lemmas, form spellings
base_lang_wiki = 'arwiki' -- Wikipedia link
formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
local function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
jsh2hk8vt24fbdb64o5xmpkqkidv9db
نقاش الوحدة:معجمية ويكي بيانات
829
237682
1090004
2026-05-15T19:14:59Z
Mdktb
25941
/* استعمال وحدة:Arguments */ قسم جديد
1090004
wikitext
text/x-wiki
== استعمال وحدة:Arguments ==
مرحبًا @[[مستخدم:ForzaGreen|ForzaGreen]]، مجرد استفسار، أليس الأفضل أن تُستدعى وحدة [[وحدة:Arguments|Arguments]] لمعالجة وسائط القالب، حاليًا فراغ بسيط قبل أو بعد معرّف المعجمية يُظهر فشلا ورسالة خطأ --[[مستخدم:Mdktb|Mdktb]] ([[نقاش المستخدم:Mdktb|نقاش]]) 19:14، 15 مايو 2026 (ت ع م)
qhb9unwubkm84e51qfmmkz3kxp43lm1
1090005
1090004
2026-05-15T19:20:20Z
Mdktb
25941
/* استعمال وحدة:Arguments */
1090005
wikitext
text/x-wiki
== استعمال وحدة:Arguments ==
مرحبًا @[[مستخدم:ForzaGreen|ForzaGreen]]، مجرد استفسار، أليس الأفضل أن تُستدعى وحدة [[وحدة:Arguments|Arguments]] لمعالجة وسائط القالب، حاليًا فراغ بسيط قبل أو بعد معرّف المعجمية يُظهر فشلا ورسالة خطأ، كذلك الخيارات مثل [[خاص:وصلة دائمة/1090003#L-920|<code>{ parentOnly = true }</code>]] لا تعمل، وغير مدعومة --[[مستخدم:Mdktb|Mdktb]] ([[نقاش المستخدم:Mdktb|نقاش]]) 19:14، 15 مايو 2026 (ت ع م)
oo40bmytovyiptv67sxq2u7cfa2p9it
1090018
1090005
2026-05-15T22:31:25Z
ForzaGreen
28665
/* استعمال وحدة:Arguments */ ردّ
1090018
wikitext
text/x-wiki
== استعمال وحدة:Arguments ==
مرحبًا @[[مستخدم:ForzaGreen|ForzaGreen]]، مجرد استفسار، أليس الأفضل أن تُستدعى وحدة [[وحدة:Arguments|Arguments]] لمعالجة وسائط القالب، حاليًا فراغ بسيط قبل أو بعد معرّف المعجمية يُظهر فشلا ورسالة خطأ، كذلك الخيارات مثل [[خاص:وصلة دائمة/1090003#L-920|<code>{ parentOnly = true }</code>]] لا تعمل، وغير مدعومة --[[مستخدم:Mdktb|Mdktb]] ([[نقاش المستخدم:Mdktb|نقاش]]) 19:14، 15 مايو 2026 (ت ع م)
:مرحبا @[[مستخدم:Mdktb|Mdktb]]، شكرا لك على الرسالة. أظن أنك تقصد قالب {{قا|معجمية}}. في الحقيقة لم أكن أعرف [[وحدة:Arguments]]، وليس لي مانع في استعمالها. [[مستخدم:ForzaGreen|وائل]] ([[نقاش المستخدم:ForzaGreen|نقاش]]) 22:31، 15 مايو 2026 (ت ع م)
kejq0we6j52tqf1wjavu1zxyyia2hgt
1090019
1090018
2026-05-15T22:40:58Z
Mdktb
25941
/* استعمال وحدة:Arguments */ ردّ
1090019
wikitext
text/x-wiki
== استعمال وحدة:Arguments ==
مرحبًا @[[مستخدم:ForzaGreen|ForzaGreen]]، مجرد استفسار، أليس الأفضل أن تُستدعى وحدة [[وحدة:Arguments|Arguments]] لمعالجة وسائط القالب، حاليًا فراغ بسيط قبل أو بعد معرّف المعجمية يُظهر فشلا ورسالة خطأ، كذلك الخيارات مثل [[خاص:وصلة دائمة/1090003#L-920|<code>{ parentOnly = true }</code>]] لا تعمل، وغير مدعومة --[[مستخدم:Mdktb|Mdktb]] ([[نقاش المستخدم:Mdktb|نقاش]]) 19:14، 15 مايو 2026 (ت ع م)
:مرحبا @[[مستخدم:Mdktb|Mdktb]]، شكرا لك على الرسالة. أظن أنك تقصد قالب {{قا|معجمية}}. في الحقيقة لم أكن أعرف [[وحدة:Arguments]]، وليس لي مانع في استعمالها. [[مستخدم:ForzaGreen|وائل]] ([[نقاش المستخدم:ForzaGreen|نقاش]]) 22:31، 15 مايو 2026 (ت ع م)
::@[[مستخدم:ForzaGreen|ForzaGreen]] أقصد في هذه الوحدة، لاحظ هذا [[خاص:فرق/1090017|التعديل]] في صفحة الملعب، كذلك صديقي يوجد العديد من المتغيرات غير معرفّة local، بل وبعضها يُستعمل بذات الاسم في دوال مختلفة، وكنت افكر بوجود صفحة وحدة فرعية تحوي i18n و formatter_urls والمتغيرات التي تبدأ بـ base_lang_ ويجري استدعائها، مجرد فصل تنظيمي لا أكثر، تحياتي --[[مستخدم:Mdktb|Mdktb]] ([[نقاش المستخدم:Mdktb|نقاش]]) 22:40، 15 مايو 2026 (ت ع م)
dn0rvg8bll44kj5p2ivdaxev02de4ld
أَمَدَّ
0
237683
1090006
2026-05-15T19:37:17Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090006
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1483787}}
=== المعاني ===
'''أَمَدَّ''' {{أفعل}}
{{معجمية|L1483787|معاني}}
=== النطق ===
* {{أصد-عر|أَمَدَّ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=مدد|وزن=أفعل}}
=== المراجع ===
{{مراجع}}
k1qb6o1doi0r12nw0m1nbev1e0nuig0
أَطَرَّ
0
237684
1090007
2026-05-15T19:39:11Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090007
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1538083}}
=== المعاني ===
'''أَطَرَّ''' {{أفعل}}
{{معجمية|L1538083|معاني}}
=== النطق ===
* {{أصد-عر|أَطَرَّ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=طرر|وزن=أفعل}}
=== المراجع ===
{{مراجع}}
i8bgk49euwy5p3m5grlu6fclt65054e
جَحْدَلَ
0
237685
1090008
2026-05-15T20:02:44Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090008
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1533741}}
=== المعاني ===
'''جَحْدَلَ''' {{فعلل}}
{{معجمية|L1533741|معاني}}
=== النطق ===
* {{أصد-عر|جَحْدَلَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=جحدل|وزن=فعلل}}
=== المراجع ===
{{مراجع}}
eympqnzz8yr6omglkva6buxugytnzhl
ثَقَفَ
0
237686
1090009
2026-05-15T20:04:33Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090009
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1480566}}
=== المعاني ===
'''ثَقَفَ''' {{نصر}}
{{معجمية|L1480566|معاني}}
=== النطق ===
* {{أصد-عر|ثَقَفَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=ثقف|وزن=فعَل يفعُل}}
=== المراجع ===
{{مراجع}}
srkwci37fa58k6b4y2f290xw704z9lu
تَثَقَّفَ
0
237687
1090010
2026-05-15T20:05:27Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090010
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1497691}}
=== المعاني ===
'''تَثَقَّفَ''' {{تفعّل}}
{{معجمية|L1497691|معاني}}
=== النطق ===
* {{أصد-عر|تَثَقَّفَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=ثقف|وزن=تفعّل}}
=== المراجع ===
{{مراجع}}
228kdw481hdcdp9wvg2qzylc0mfs3j5
تَثَاقَفَ
0
237688
1090011
2026-05-15T20:06:20Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090011
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1485017}}
=== المعاني ===
'''تَثَاقَفَ''' {{تفاعل}}
{{معجمية|L1485017|معاني}}
=== النطق ===
* {{أصد-عر|تَثَاقَفَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=ثقف|وزن=تفاعل}}
=== المراجع ===
{{مراجع}}
exu3kmvfbajxmut6mnhewfqy359tlhn
تَتَايَعَ
0
237689
1090012
2026-05-15T20:08:23Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090012
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1533508}}
=== المعاني ===
'''تَتَايَعَ''' {{تفاعل}}
{{معجمية|L1533508|معاني}}
=== النطق ===
* {{أصد-عر|تَتَايَعَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=تيع|وزن=تفاعل}}
=== المراجع ===
{{مراجع}}
bj3p8uo4l3qtojg35ex8kirhu5wflli
تَاجَ
0
237690
1090013
2026-05-15T20:09:10Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090013
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1544250}}
=== المعاني ===
'''تَاجَ''' {{نصر}}
{{معجمية|L1544250|معاني}}
=== النطق ===
* {{أصد-عر|تَاجَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=توج|وزن=فعَل يفعُل}}
=== المراجع ===
{{مراجع}}
gdap8otz68dkcxgvgkivvnuxbtsyukj
بَيْقَرَ
0
237691
1090014
2026-05-15T20:13:59Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090014
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1533359}}
=== المعاني ===
'''بَيْقَرَ''' {{فعلل}}
{{معجمية|L1533359|معاني}}
=== النطق ===
* {{أصد-عر|بَيْقَرَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=بيقر|وزن=فعلل}}
=== المراجع ===
{{مراجع}}
s18ppehsjns76nux4onpo6gb3nau0ru
بَيَّضَ
0
237692
1090015
2026-05-15T20:15:48Z
رِفْد
37814
إنشاء صفحة فعل من بيانات المعاجم (ar-senses tool)
1090015
wikitext
text/x-wiki
== {{اللغة|عربية}} ==
{{صندوق معلومات فعل|L1487286}}
=== المعاني ===
'''بَيَّضَ''' {{فعّل}}
{{معجمية|L1487286|معاني}}
=== النطق ===
* {{أصد-عر|بَيَّضَ}}
{{-}}
=== التصريفات ===
{{تصريف|جذر=بيض|وزن=فعّل}}
=== المراجع ===
{{مراجع}}
5ihl2oaztdkrsxjwfskcngq1stpbgtv
وحدة:معجمية ويكي بيانات/ملعب
828
237693
1090016
2026-05-15T20:24:01Z
Mdktb
25941
+ جلب من [[خاص:وصلة دائمة/1090003|الوحدة]]
1090016
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Inline i18n configuration for Arabic
local i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
-- Inline getArgs replacement
local function getArgs(frame)
local args = {}
local parent_args = frame:getParent() and frame:getParent().args or {}
-- Merge frame.args and parent_args
for k, v in pairs(frame.args) do
if v ~= '' then args[k] = v end
end
for k, v in pairs(parent_args) do
if v ~= '' and args[k] == nil then args[k] = v end
end
return args
end
base_lang_code_labels = 'ar' -- Item labels/descriptions/aliases, sense descriptions
base_lang_code_forms = 'ar' -- Lexeme lemmas, form spellings
base_lang_wiki = 'arwiki' -- Wikipedia link
formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
local function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
jsh2hk8vt24fbdb64o5xmpkqkidv9db
1090017
1090016
2026-05-15T20:28:36Z
Mdktb
25941
الاعتماد على وحدة Arguments
1090017
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Inline i18n configuration for Arabic
local i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
-- Fetch arguments
local getArgs = require('Module:Arguments').getArgs
base_lang_code_labels = 'ar' -- Item labels/descriptions/aliases, sense descriptions
base_lang_code_forms = 'ar' -- Lexeme lemmas, form spellings
base_lang_wiki = 'arwiki' -- Wikipedia link
formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
local function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
r8xx2mcyyl2n8uglq1o2sw9wyz2rt2l
1090021
1090017
2026-05-15T23:43:15Z
Mdktb
25941
فصل عن الوحدة في صفحة فرعية
1090021
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Configuration
local config = require('Module:معجمية ويكي بيانات/ضبط/ملعب')
local i18n = config.i18n
local formatter_urls = config.formatter_urls
local base_lang_code_labels = config.base_lang.labels
local base_lang_code_forms = config.base_lang.forms
local base_lang_wiki = config.base_lang.wiki
-- Fetch arguments
local getArgs = require('Module:Arguments').getArgs
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
template = ''
stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for i, stmt in pairs(sense:getAllStatements(property_id)) do
stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for i, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for i, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for i, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
first_sense_image = ''
sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for i, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for i, v in ipairs(new_notes) do
if i == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
local function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
lexeme_id = args[1]
current_lexeme = mw.wikibase.getEntity(lexeme_id)
current_language = current_lexeme:getLanguage()
current_category = current_lexeme:getLexicalCategory()
references_seen = {}
sections = {}
cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
etymology = getEtymology ( current_lexeme )
combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
p49jdd5sgdo1wqp8dox8x4vv4mthn23
1090022
1090021
2026-05-16T00:15:30Z
Mdktb
25941
حل إشكاليات متغيرات يفترض أن تكون local وإشكاليات for loop
1090022
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Configuration
local config = require('Module:معجمية ويكي بيانات/ضبط/ملعب')
local i18n = config.i18n
local formatter_urls = config.formatter_urls
local base_lang_code_labels = config.base_lang.labels
local base_lang_code_forms = config.base_lang.forms
local base_lang_wiki = config.base_lang.wiki
-- Fetch arguments
local getArgs = require('Module:Arguments').getArgs
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
local template = ''
local stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
local article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
local property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
if next(property_source) ~= nil then
local source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
local source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
local formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
local new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
local examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
local meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for s, stmt in pairs(sense:getAllStatements(property_id)) do
local stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
local stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for s, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for s, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for s, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
local first_sense_image = ''
local sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
local externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
local sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for s, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for s, v in ipairs(new_notes) do
if s == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
local examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
local base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
local function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
local base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
local lexeme_id = args[1]
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
local current_language = current_lexeme:getLanguage()
local current_category = current_lexeme:getLexicalCategory()
local references_seen = {}
local sections = {}
local cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
local etymology = getEtymology ( current_lexeme )
local combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
local pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
local meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
local external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
hwdyx976zta3w4yirf3ft3e2ea6w6fh
1090023
1090022
2026-05-16T00:45:51Z
Mdktb
25941
تحسين تعريفات متغيرات ودوال
1090023
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Configuration
local config = require('Module:معجمية ويكي بيانات/ضبط/ملعب')
local i18n = config.i18n
local formatter_urls = config.formatter_urls
local base_lang_code_labels = config.base_lang.labels
local base_lang_code_forms = config.base_lang.forms
local base_lang_wiki = config.base_lang.wiki
-- Fetch arguments
local getArgs = require('Module:Arguments').getArgs
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
local template = ''
local stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
local article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
local property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
local source_name
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
local formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
local new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
local examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
local meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for s, stmt in pairs(sense:getAllStatements(property_id)) do
local stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
local stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for s, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for s, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for s, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
local first_sense_image = ''
local sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
local externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
local sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for s, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for s, v in ipairs(new_notes) do
if s == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
local examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
local base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local getEtymology
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
local base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
local lexeme_id = args[1]
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
local current_language = current_lexeme:getLanguage()
local current_category = current_lexeme:getLexicalCategory()
local references_seen = {}
local sections = {}
local cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
local etymology = getEtymology ( current_lexeme )
local combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
local pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
local meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
local external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
6q9ztply458rypto72t61svmnzj175h
1090024
1090023
2026-05-16T10:22:03Z
Mdktb
25941
أوفر في الذاكرة
1090024
Scribunto
text/plain
-- وحدة:معجمية ويكي بيانات
-- 🚧 Work in progress 🚧
-- By: Wael (User:ForzaGreen)
-- Imports data from Wikidata lexemes for Arabic entries in Wiktionary.
-- TODOs:
-- - ✅ Handle missing senses. Edit icon to wikidata lexeme's senses + page link to Wiktionary:Wikidata
-- - ✅ Categories: add categories for pages with/without senses
-- - ✅ References: group references when they are identical
-- - ✅ References: use references from "usage example"
-- - ✅ Create "ويكاموس:ويكي بيانات" page
-- - ✅ Template for wikidata meanings: قالب:معجمية, and docs
-- - Test Etymology
-- - Test Pronunciation
-- - Test External links
-- - (later) Add module/template for "Wikidata has a lexeme related to 'word' (Lxxxx)"
-- - (later) Display "quotations" (issue: different from "gloss quote"), "synonyms", ...
local p = {}
-- Configuration
local config = mw.loadData('Module:معجمية ويكي بيانات/ضبط/ملعب')
local i18n = config.i18n
local formatter_urls = config.formatter_urls
local base_lang_code_labels = config.base_lang.labels
local base_lang_code_forms = config.base_lang.forms
local base_lang_wiki = config.base_lang.wiki
-- Fetch arguments
local getArgs = require('Module:Arguments').getArgs
-- Return the first form of the lexeme which has exactly the given grammatical feature.
local function formWithSingleGrammaticalFeature( lexeme, item_id )
for i, form in pairs( lexeme:getForms() ) do
local grammaticalFeatures = form:getGrammaticalFeatures()
if #grammaticalFeatures == 1 and grammaticalFeatures[1] == item_id then
return form
end
end
return nil
end
-- Return the representation of the form in the given language code,
-- or the first representation otherwise.
local function representationInLanguage( form, language_code )
for i, representation in pairs( form:getRepresentations() ) do
if representation[2] == language_code then
return representation
end
end
return form:getRepresentations()[1]
end
local function getArticleLinkTemplate(frame, stmt_value)
local template = ''
local stmt_item = mw.wikibase.getEntity(stmt_value)
if stmt_item:getSitelink(base_lang_wiki) ~= nil then
template = frame:expandTemplate{
title=i18n['template_wikipedia'],
args={stmt_item:getSitelink(base_lang_wiki)}
}
end
return template
end
local function getArticleLinks ( frame, sense )
local article_links = ''
for i, stmt in pairs(sense:getAllStatements('P5137')) do -- Item for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
for i, stmt in pairs(sense:getAllStatements('P9970')) do -- Predicate for this sense
local stmt_value = stmt.mainsnak.datavalue.value.id
article_links = article_links .. getArticleLinkTemplate(frame, stmt_value)
end
return article_links
end
local function getExternalLinks ( lexeme )
local external_links = {}
for property_id, formatter_url in pairs(formatter_urls) do
for i, stmt in ipairs(lexeme:getAllStatements(property_id)) do
local property_source = mw.wikibase.getBestStatements(property_id, 'P9073') -- Applicable 'stated in' value
local source_name
if next(property_source) ~= nil then
source_name = mw.wikibase.getLabel(property_source[1].mainsnak.datavalue.value.id)
if source_name == nil then
source_name = property_source[1].mainsnak.datavalue.value.id
end
else
source_name = mw.wikibase.getLabel(property_id)
if source_name == nil then
source_name = property_id
end
end
-- Encode spaces in URLs as + signs for better URL compatibility
local formatted_link = mw.ustring.gsub(mw.ustring.gsub(formatter_url, '$1', stmt.mainsnak.datavalue.value), ' ', '+')
local new_link = '* [' .. formatted_link .. ' ' .. source_name .. ']'
table.insert(external_links, new_link)
end
end
return table.concat(external_links, '\n')
end
local function termSpan( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( text )
return tostring( span )
end
local function termLink( term )
local text = term[1]
local lang = term[2]
local dir = mw.language.new( lang ):getDir()
local span = mw.html.create( 'span' )
span:attr( 'lang', lang )
:attr( 'dir', dir )
:wikitext( '[[' .. text .. ']]' )
return tostring( span )
end
local function getLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termSpan(rep)
else
lemma_string = lemma_string .. '/' .. termSpan(rep)
end
end
return lemma_string
end
local function getLinkedLemmata( current_lexeme )
local lemma_string = ''
for i, rep in pairs(current_lexeme:getLemmas()) do
if lemma_string == '' then
lemma_string = termLink(rep)
else
lemma_string = lemma_string .. '/' .. termLink(rep)
end
end
return lemma_string
end
-- Helper function to generate a unique reference ID based on source and qualifiers
local function generateReferenceId(source_id, qualifiers)
local id_parts = {source_id}
if qualifiers then
-- Include volume (P478) in ID
if qualifiers['P478'] then
table.insert(id_parts, 'v' .. qualifiers['P478'][1].datavalue.value)
end
-- Include page(s) (P304) in ID
if qualifiers['P304'] then
table.insert(id_parts, 'p' .. qualifiers['P304'][1].datavalue.value)
end
end
return table.concat(id_parts, '-')
end
-- Helper function to format a Wikidata reference using استشهاد بويكي بيانات template
-- Can accept either a statement (for P1343) or a reference object (for P8394 references)
local function formatWikidataReference(frame, source_id, qualifiers)
local ref_args = {source_id}
-- Add qualifiers if present
if qualifiers then
-- P478 = volume (ج)
if qualifiers['P478'] then
ref_args['ج'] = qualifiers['P478'][1].datavalue.value
end
-- P304 = page(s) (ص)
if qualifiers['P304'] then
ref_args['ص'] = qualifiers['P304'][1].datavalue.value
end
end
return frame:expandTemplate{
title='استشهاد بويكي بيانات',
args=ref_args
}
end
local function getExamples( current_lexeme, sense_id, frame, references_seen )
local examples = mw.html.create('dl')
for i, stmt in pairs(current_lexeme:getAllStatements('P5831')) do -- Usage example
if stmt.qualifiers and stmt.qualifiers['P6072'] and stmt.qualifiers['P6072'][1].datavalue.value.id == sense_id then -- Lexeme sense for this example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
end
for i, stmt in pairs(mw.wikibase.getAllStatements(sense_id, 'P5831')) do -- Usage example
-- Support multi-line examples by converting ' / ' to line breaks
local example_text = mw.ustring.gsub(stmt.mainsnak.datavalue.value.text, ' / ','<br/>')
local example_lang = stmt.mainsnak.datavalue.value.language
-- Highlight the form if P5830 (subject lexeme form) is present
if stmt.qualifiers and stmt.qualifiers['P5830'] and stmt.qualifiers['P5830'][1] then
local example_form = mw.wikibase.getEntity(stmt.qualifiers['P5830'][1].datavalue.value.id) -- Lexeme form for this example
-- Try P1810 qualifier first (title/name qualifier as string), then representation
local example_form_str = nil
if stmt.qualifiers['P1810'] ~= nil then
example_form_str = stmt.qualifiers['P1810'][1].datavalue.value
end
if example_form_str == nil then
example_form_str = example_form:getRepresentation(base_lang_code_forms)
end
if example_form_str == nil then
example_form_str = example_form:getRepresentations()[1][1]
end
example_text = mw.ustring.gsub(example_text, example_form_str, "'''" .. example_form_str .. "'''")
end
local example_str = termSpan({example_text, example_lang})
-- Add references if present
local example_refs = ''
if frame and references_seen and stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
example_refs = frame:extensionTag('ref', '', {name = ref_id})
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
example_refs = frame:extensionTag('ref', citation, {name = ref_id})
end
end
end
examples:tag('dd'):wikitext("''" .. example_str .. "''" .. example_refs):done()
end
return tostring(examples)
end
local function getLanguageForCategories ( frame, lang_id )
-- No special handling needed for Arabic
return lang_id
end
local function getCategory ( frame, current_lexeme )
local lang_id = current_lexeme:getLanguage()
local cat_id = current_lexeme:getLexicalCategory()
local cat_text = mw.wikibase.getLabelByLang( cat_id, base_lang_code_labels )
lang_id = getLanguageForCategories(frame , lang_id)
if i18n['categories'][lang_id] ~= nil then
if i18n['categories'][lang_id][cat_id] ~= nil then
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id][cat_id] .. ']]'
elseif i18n['categories'][lang_id]['_'] ~= nil then
-- Fallback category if specific category not found
cat_text = cat_text .. '[[Category:' .. i18n['categories'][lang_id]['_'] .. ']]'
end
end
return cat_text
end
-- Add category for pages using Wikidata
local function addWikidataUsageCategory()
return '[[Category:' .. i18n['category_uses_wikidata'] .. ']]'
end
local createicon = function(langcode, entityID, propertyID)
langcode = langcode or ""
propertyID = propertyID or ""
local icon = " <span class='penicon autoconfirmed-show'>[["
-- " <span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge
.. "File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="
.. i18n['edit_wikidata']
.. "|link=https://www.wikidata.org/entity/" .. entityID
if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end
if propertyID ~= "" then icon = icon .. "#" .. propertyID end
icon = icon .. "|" .. i18n['edit_wikidata'] .. "]]</span>"
return icon
end
local function getMeanings ( frame, args, current_lexeme, references_seen )
if #current_lexeme:getSenses() == 0 then
local lexeme_id = current_lexeme:getId()
-- Build Wikidata logo icon (similar to ar-verb-infobox.lua footer)
local wikidata_logo = '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
-- Build edit icon that links directly to the senses section
local edit_icon = ' <span class="penicon autoconfirmed-show">[['
.. 'File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt='
.. i18n['edit_wikidata']
.. '|link=https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
.. '|' .. i18n['edit_wikidata'] .. ']]</span>'
-- Build external link to Wikidata senses section (same as edit icon)
local wikidata_senses_url = 'https://www.wikidata.org/wiki/Lexeme:' .. lexeme_id .. '?uselang=ar#senses'
local missing_senses_html = mw.html.create('div')
:addClass('wikidata-missing-senses')
:css('font-style', 'italic')
:wikitext(i18n['text_missing_senses'] .. ' ')
:wikitext(wikidata_logo .. ' ')
:wikitext('[' .. wikidata_senses_url .. ' ' .. lexeme_id .. ']')
:wikitext(edit_icon .. '. ')
:wikitext(i18n['text_more_info'] .. ' ')
:wikitext('[[' .. i18n['help_page'] .. ']].')
:wikitext('[[Category:' .. i18n['category_missing_senses'] .. ']]')
return tostring(missing_senses_html)
end
local meanings = mw.html.create( 'ol' )
for i, sense in pairs(current_lexeme:getSenses()) do
local gloss_text_parts = {}
local main_gloss_text = frame:expandTemplate{
title=i18n['template_anchor'],
args={sense:getId()}
}
local specifiers = {}
for k, property_id in ipairs({'P6084', 'P6191', 'P9488'}) do -- Location where sense is used, register in which sense is used, field of usage
for s, stmt in pairs(sense:getAllStatements(property_id)) do
local stmt_value = stmt.mainsnak.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
if #specifiers > 0 then
main_gloss_text = main_gloss_text .. "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
if sense:getGloss( base_lang_code_labels ) ~= nil then
main_gloss_text = main_gloss_text .. sense:getGloss( base_lang_code_labels)
else
local other_gloss_text = nil
local other_gloss_lang = nil
-- First try to get labels from P5137 (item for this sense)
local item_label_gloss_parts = {}
for k, stmt in pairs(sense:getAllStatements('P5137')) do
local stmt_value = stmt.mainsnak.datavalue.value.id
local stmt_label = mw.wikibase.getLabelByLang(stmt_value, base_lang_code_labels)
if stmt_label ~= nil then
table.insert(item_label_gloss_parts, '[[:d:' .. stmt_value .. '|' .. stmt_label .. ']]')
end
end
if #item_label_gloss_parts > 0 then
other_gloss_text = table.concat(item_label_gloss_parts, '; ')
end
-- If no item labels found, try fallback languages
if other_gloss_text == nil then
for s, fallback_lang in ipairs(mw.language.getFallbacksFor( base_lang_code_labels )) do
if sense:getGloss( fallback_lang ) ~= nil then
other_gloss_text, other_gloss_lang = sense:getGloss( fallback_lang )
end
end
if other_gloss_lang == nil then
local glosses = sense:getGlosses()
for j, gloss in pairs(glosses) do
other_gloss_text = gloss[1]
other_gloss_lang = gloss[2]
break
end
end
main_gloss_text = main_gloss_text .. other_gloss_text .. "<sup><em>" .. mw.language.fetchLanguageName(other_gloss_lang, base_lang_code_labels) .. "</em></sup>"
else
main_gloss_text = main_gloss_text .. "''" .. other_gloss_text .. "''"
end
end
table.insert(gloss_text_parts, main_gloss_text .. createicon(base_lang_code_labels, sense:getId()))
for s, stmt in pairs(sense:getAllStatements('P8394')) do -- P8394 = gloss quote
local quote_text = termSpan({stmt.mainsnak.datavalue.value.text, stmt.mainsnak.datavalue.value.language})
table.insert(gloss_text_parts, '"' .. quote_text .. '"')
-- Format citation using استشهاد بويكي بيانات template if references exist
if stmt.references and stmt.references[1] ~= nil then
local ref = stmt.references[1]
-- Try to find P248 (stated in) in the reference snaks
if ref.snaks and ref.snaks['P248'] and ref.snaks['P248'][1] then
local source_id = ref.snaks['P248'][1].datavalue.value.id
local ref_id = generateReferenceId(source_id, ref.snaks)
local citation = formatWikidataReference(frame, source_id, ref.snaks)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
end
end
for s, stmt in pairs(sense:getAllStatements('P1343')) do -- P1343 = described by source
local source_id = stmt.mainsnak.datavalue.value.id
local citation = formatWikidataReference(frame, source_id, stmt.qualifiers)
local ref_id = generateReferenceId(source_id, stmt.qualifiers)
-- Track and group references
if references_seen then
if references_seen[ref_id] then
-- Reference already exists, use named reference without content
table.insert(gloss_text_parts, frame:extensionTag('ref', '', {name = ref_id}))
else
-- First occurrence, create named reference with content
references_seen[ref_id] = true
table.insert(gloss_text_parts, frame:extensionTag('ref', citation, {name = ref_id}))
end
else
-- No tracking, just add the reference
table.insert(gloss_text_parts, frame:extensionTag('ref', citation))
end
end
local first_sense_image = ''
local sense_images = sense:getAllStatements('P18')
if next(sense_images) ~= nil then
first_sense_image = sense_images[1].mainsnak.datavalue.value
end
if first_sense_image ~= '' then
table.insert(gloss_text_parts, '[[File:' .. first_sense_image .. "|thumb|'''" .. getLemmata(current_lexeme) .. "'''—" .. main_gloss_text .. ']]')
end
local externallinks = getArticleLinks(frame, sense)
if externallinks ~= '' then
table.insert(gloss_text_parts, '— ' .. externallinks)
end
local new_notes = {}
local sense_keys = { sense:getId(), string.sub(sense:getId(), string.find(sense:getId(), '-')+1) }
for s, v in ipairs(sense_keys) do
if args[v] ~= nil then
table.insert(new_notes, args[v])
end
end
if #new_notes > 0 then
for s, v in ipairs(new_notes) do
if s == 1 then
table.insert(gloss_text_parts, '<br/>' .. v)
else
table.insert(gloss_text_parts, v)
end
end
end
local examples = getExamples ( current_lexeme, sense:getId(), frame, references_seen )
-- Join gloss parts with spaces for inline elements like refs, newlines for block elements
local gloss_text = ''
for idx, part in ipairs(gloss_text_parts) do
if idx == 1 then
gloss_text = part
elseif part:match('^<br/>') or part:match('^%[%[File:') then
-- Block-level elements get newlines
gloss_text = gloss_text .. '\n' .. part
elseif part:match('^\127') or part:match('^<ref') then
-- Strip markers starting with \127 or explicit <ref> tags
gloss_text = gloss_text .. part
else
-- Inline elements (refs, quotes) get spaces
gloss_text = gloss_text .. ' ' .. part
end
end
meanings:tag('li'):wikitext(gloss_text):wikitext(examples)
end
-- Add category for lexemes with senses
meanings:wikitext('[[Category:' .. i18n['category_has_senses'] .. ']]')
return meanings
end
local function get_pronunciation_base_form( current_lexeme )
local base_form = nil
-- (!) Words in other languages with different base forms can be added here with new if statements.
-- For Arabic, use the first available form
if base_form == nil then
for i, form in pairs(current_lexeme:getForms()) do
base_form = form
break
end
end
return base_form
end
local getEtymology
local function getCombines ( current_lexeme )
local combines = ''
local index_mappings = {}
for i, stmt in pairs(current_lexeme:getAllStatements('P5238')) do
if stmt.qualifiers and stmt.qualifiers['P1545'] ~= nil then -- Series ordinal
local current_index = tonumber(stmt.qualifiers['P1545'][1].datavalue.value)
index_mappings[current_index] = stmt
end
end
if #index_mappings ~= 0 then
for i, stmt in ipairs(index_mappings) do
local part_lexeme_id = stmt.mainsnak.datavalue.value.id
local part_lexeme = mw.wikibase.getEntity(part_lexeme_id)
local current_substring = getLinkedLemmata(part_lexeme)
-- Add recursive etymology for compound parts
local part_etymology = getEtymology(part_lexeme)
if part_etymology ~= '' then
current_substring = current_substring .. ' (← ' .. part_etymology .. ')'
end
if combines == '' then
combines = current_substring
else
combines = combines .. ' + ' .. current_substring
end
end
end
return combines
end
function getEtymology ( current_lexeme )
-- Recursive etymology support (no depth limit)
local etymology = ''
local current_combines = getCombines(current_lexeme)
if #current_lexeme:getAllStatements('P5191') == 0 then
return current_combines
end
for i, stmt in pairs(current_lexeme:getAllStatements('P5191')) do
local origin_lexeme = mw.wikibase.getEntity(stmt.mainsnak.datavalue.value.id)
local origin_lexeme_lang = origin_lexeme:getLanguage()
local origin_origin = getEtymology(origin_lexeme) -- Recursive call
local new_etymology_string = ''
if origin_origin ~= '' then
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ') ← ' .. origin_origin
else
new_etymology_string = getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
if etymology == '' then
etymology = new_etymology_string
else
etymology = etymology .. ' ' .. getLinkedLemmata(origin_lexeme) .. ' (' .. mw.wikibase.getLabel(origin_lexeme_lang) .. ')'
end
end
if current_combines ~= '' then
etymology = etymology .. '<br/>(' .. current_combines .. ')'
end
return etymology
end
local function getPronunciation ( frame, current_lexeme )
local pronunciations = {}
local base_form = get_pronunciation_base_form(current_lexeme)
if base_form ~= nil then
-- P443 = Audio pronunciation
for i, stmt in pairs(base_form:getAllStatements('P443')) do
local pronunciation_file = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. frame:expandTemplate{
title= i18n['template_audio'],
args = {current_lexeme:getLemmas()[1][2], pronunciation_file } -- TODO: find situations where the proper category is not added
})
end
-- P898 = IPA transcription
for i, stmt in pairs(base_form:getAllStatements('P898')) do
local ipa_text = stmt.mainsnak.datavalue.value
local specifier_text = ''
local specifiers = {}
if stmt.qualifiers ~= nil then
for k, property_id in ipairs({'P5237'}) do -- P5237 = Pronunciation manner
if stmt.qualifiers[property_id] then
for l, qual in pairs(stmt.qualifiers[property_id]) do
local stmt_value = qual.datavalue.value.id
table.insert(specifiers, mw.wikibase.getLabel(stmt_value))
end
end
end
end
if #specifiers > 0 then
specifier_text = "(''" .. table.concat(specifiers, "'', ''") .. "'') "
end
-- Use IPA template if available, otherwise just format as IPA
local pronunciation = table.insert(pronunciations, '* ' .. specifier_text .. '{{آيبا|ar|' .. ipa_text .. '}}')
end
end
return table.concat(pronunciations, '\n')
end
local function heading_level(text, level)
local heading_delimiter = string.rep('=', level)
return heading_delimiter .. ' ' .. text .. ' ' .. heading_delimiter
end
local function get_any_notes(sections, args, keys)
local notes = {}
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(notes, args[v])
end
end
return notes
end
local function add_specific_notes(sections, notes)
for i, v in ipairs(notes) do
table.insert(sections, v)
end
end
local function add_any_notes(sections, args, keys)
for i, v in ipairs(keys) do
if args[v] ~= nil then
table.insert(sections, args[v])
end
end
end
-- Public function: Display meanings/senses only
-- Usage: {{#invoke:معجمية ويكي بيانات|meanings|L12345}}
function p.meanings(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return '<span class="error">خطأ: يجب تحديد معرف المدخل المعجمي من ويكي بيانات (مثال: L12345)</span>'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return '<span class="error">خطأ: لم يتم العثور على المدخل المعجمي ' .. lexeme_id .. ' في ويكي بيانات</span>'
end
-- Check if it's Arabic (Q13955)
local lang_id = current_lexeme:getLanguage()
if lang_id ~= 'Q13955' then
local lang_name = mw.wikibase.getLabel(lang_id) or lang_id
return '<span class="error">تحذير: هذا المدخل للغة ' .. lang_name .. ' وليس العربية (Q13955)</span>'
end
local sections = {}
local references_seen = {}
-- Add meanings section
local meanings = getMeanings(frame, args, current_lexeme, references_seen)
table.insert(sections, tostring(meanings))
-- -- Only show references section if there are references
-- W: don't show references. It's to be added outside with {{مراجع}}
-- if next(references_seen) ~= nil then
-- table.insert(sections, frame:extensionTag('references'))
-- end
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections, '\n\n')
end
-- Public function: Debug information
-- Usage: {{#invoke:معجمية ويكي بيانات|debug|L12345}}
function p.debug(frame)
local args = getArgs(frame)
local lexeme_id = args[1]
if not lexeme_id or lexeme_id == '' then
return 'Error: No lexeme ID provided'
end
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
if not current_lexeme then
return 'Error: Lexeme ' .. lexeme_id .. ' not found'
end
local debug_info = {}
table.insert(debug_info, '=== Debug Info for ' .. lexeme_id .. ' ===')
table.insert(debug_info, 'Language: ' .. (mw.wikibase.getLabel(current_lexeme:getLanguage()) or current_lexeme:getLanguage()))
table.insert(debug_info, 'Lexical Category: ' .. (mw.wikibase.getLabel(current_lexeme:getLexicalCategory()) or current_lexeme:getLexicalCategory()))
table.insert(debug_info, 'Lemmas: ' .. getLemmata(current_lexeme))
table.insert(debug_info, 'Number of senses: ' .. #current_lexeme:getSenses())
table.insert(debug_info, 'Number of forms: ' .. #current_lexeme:getForms())
return '<pre>' .. table.concat(debug_info, '\n') .. '</pre>'
end
function p.all( frame )
local args = getArgs(frame, { parentOnly = true })
local lexeme_id = args[1]
local current_lexeme = mw.wikibase.getEntity(lexeme_id)
local current_language = current_lexeme:getLanguage()
local current_category = current_lexeme:getLexicalCategory()
local references_seen = {}
local sections = {}
local cat_text = '===' .. getCategory ( frame, current_lexeme ) .. frame:expandTemplate{
title=i18n['template_anchor'],
args={lexeme_id}
} .. '==='
table.insert(sections, cat_text)
table.insert(sections, frame:expandTemplate{
title= i18n['template_lexeme'],
args = {lexeme_id}
})
add_any_notes(sections, args, i18n['manual_category'])
local etymology = getEtymology ( current_lexeme )
local combines = getCombines ( current_lexeme )
if etymology ~= '' or combines ~= '' then
table.insert(sections, heading_level(i18n['heading_etymology'], 4))
if etymology ~= '' then
table.insert(sections, tostring(etymology))
end
if combines ~= '' then
table.insert(sections, tostring(combines))
end
end
add_any_notes(sections, args, i18n['manual_etymology'])
local pronunciation = getPronunciation ( frame, current_lexeme )
if pronunciation ~= '' then
table.insert(sections, heading_level(i18n['heading_pronunciation'], 4))
table.insert(sections, tostring(pronunciation))
end
add_any_notes(sections, args, i18n['manual_pronunciation'])
local meanings, sense_sources = getMeanings ( frame, args, current_lexeme, references_seen )
table.insert(sections, heading_level(i18n['heading_meanings'], 4))
table.insert(sections, tostring(meanings))
add_any_notes(sections, args, i18n['manual_meaning'])
-- Only show references section if there are references or manual reference notes
local reference_notes = get_any_notes(sections, args, i18n['manual_reference'])
local has_references = next(references_seen) ~= nil
if has_references or #reference_notes > 0 then
table.insert(sections, heading_level(i18n['heading_references'], 4))
table.insert(sections, frame:extensionTag('references'))
add_specific_notes(sections, reference_notes)
end
local external_links = getExternalLinks ( current_lexeme )
if external_links ~= '' then
table.insert(sections, heading_level(i18n['heading_external_links'], 4))
table.insert(sections, external_links)
end
add_any_notes(sections, args, i18n['manual_external_link'])
-- Add Wikidata usage category
table.insert(sections, addWikidataUsageCategory())
return table.concat(sections,"\n\n")
end
-- Arabic wrapper functions for template interface
p['معاني'] = function(frame)
return p.meanings(frame)
end
return p
-- Debug usage examples:
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L12100'}})
-- =p.meanings(mw.getCurrentFrame():newChild{args={'L1478139'}})
-- =p['معاني'](mw.getCurrentFrame():newChild{args={'L12100'}})
6xhhkey2pfuta84j5unlsnzewnzzswi
وحدة:معجمية ويكي بيانات/ضبط/ملعب
828
237694
1090020
2026-05-15T23:37:53Z
Mdktb
25941
+ جلب جزئي من [[خاص:وصلة دائمة/1090003|الوحدة]]
1090020
Scribunto
text/plain
local config = {}
config.base_lang = {
labels = 'ar',
forms = 'ar',
wiki = 'ar'
}
config.i18n = {
-- Templates
template_anchor = 'مرساة', -- anchor template
template_wikipedia = 'ويكيبيديا', -- Wikipedia link template
template_audio = 'نطق', -- Audio/pronunciation template
template_lexeme = 'مدخل معجمي', -- Lexeme template
-- Headings
heading_meanings = 'المعاني', -- Meanings section
heading_etymology = 'أصل الكلمة', -- Etymology section
heading_pronunciation = 'النطق', -- Pronunciation section
heading_references = 'المراجع', -- References section
heading_external_links = 'وصلات خارجية', -- External links
-- UI text
edit_wikidata = 'عدل في ويكي بيانات',
-- Missing senses text
text_missing_senses = 'هذه الكلمة لا تحتوي على معانٍ في ويكي بيانات. ساهم بإضافة المعاني في',
text_more_info = 'للمزيد من المعلومات راجع',
help_page = 'ويكاموس:ويكي بيانات',
-- Categories for Wikidata usage
category_uses_wikidata = 'صفحات تستخدم ويكي بيانات',
category_has_senses = 'معاني من ويكي بيانات',
category_missing_senses = 'معاني فارغة من ويكي بيانات',
-- Categories (Q13955 = Modern Standard Arabic)
categories = {
['Q13955'] = {
['Q1084'] = 'أسماء عربية', -- Nouns
['Q24905'] = 'أفعال عربية', -- Verbs
['Q34698'] = 'صفات عربية', -- Adjectives
['Q380057'] = 'ظروف عربية', -- Adverbs
['_'] = 'كلمات عربية', -- Fallback for any other lexical category
}
},
-- Manual note keys (empty for now)
manual_category = {},
manual_etymology = {},
manual_pronunciation = {},
manual_meaning = {},
manual_reference = {},
manual_external_link = {},
}
config.formatter_urls = { -- https://w.wiki/ELuT
-- Multilingual
['P11512'] = 'https://ids.clld.org/units/$1',
['P11055'] = 'https://diacl.uni-frankfurt.de/Lexeme/Details/$1',
['P13258'] = 'https://www.termania.net/slovarji/presisov-vecjezicni-slovar/$1/_',
['P5912'] = 'https://oqaasileriffik.gl/dict/?lex=$1',
-- Q11051
['P11350'] = 'http://udb.gov.pk/result_details.php?word=$1',
['P13175'] = 'https://www.cfilt.iitb.ac.in/hindishabdamitra/class/CBSE/1/1/$1/?page=1',
-- Q56356571
['P11328'] = 'https://dehkhoda.ut.ac.ir/fa/dictionary/detail/$1',
['P12326'] = 'https://vazhaju.tj/word/_/$1',
['P12519'] = 'https://qamosona.com/G3/index.php/term/57,$1.xhtml',
['P12845'] = 'https://farhang.ru/lexeme/$1.html',
-- Q13955 (Arabic)
['P11038'] = 'https://ontology.birzeit.edu/lemma/$1',
['P11757'] = 'https://ontology.birzeit.edu/wordform/$1',
['P11761'] = 'https://corpus.quran.com/qurandictionary.jsp?q=$1',
['P12451'] = ' https://ontology.birzeit.edu/lexicalconcept/$1',
['P12901'] = 'http://arabiclexicon.hawramani.com/?p=$1',
-- Q9072
['P11138'] = 'https://sonaveeb.ee/worddetails/unif/$1',
['P13190'] = 'https://www.letonika.lv/groups/default.aspx?cid=$1&r=10611062',
-- Q150 (French)
['P11118'] = 'https://www.larousse.fr/dictionnaires/francais/_/$1',
['P11284'] = 'https://www.dictionnaire-academie.fr/article/A1$1',
['P11285'] = 'https://www.dictionnaire-academie.fr/article/A2$1',
['P11286'] = 'https://www.dictionnaire-academie.fr/article/A3$1',
['P11287'] = 'https://www.dictionnaire-academie.fr/article/A4$1',
['P11288'] = 'https://www.dictionnaire-academie.fr/article/A5$1',
['P11289'] = 'https://www.dictionnaire-academie.fr/article/A6$1',
['P11290'] = 'https://www.dictionnaire-academie.fr/article/A7$1',
['P11291'] = 'https://www.dictionnaire-academie.fr/article/A8$1',
['P7732'] = 'https://www.dictionnaire-academie.fr/article/A9$1',
-- Q58635
['P7820'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fpunjabipedia.org%2Ftopic.aspx%3Ftxt%3D%251&exp=%28.%2A%29&id=$1',
['P7575'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.srigranth.org%2Fservlet%2Fgurbani.dictionary%3FParam%3D%251&exp=%28.%2A%29&id=$1',
-- Q1860 (English)
['P5275'] = 'http://www.oed.com/view/Entry/$1',
['P12510'] = 'https://doi.org/10.1093/OED/$1',
['P12739'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780199571123.001.0001/m_en_gb$1',
['P12690'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195392883.001.0001/m_en_us$1',
['P12726'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195418163.001.0001/m_en_ca$1',
['P12718'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195517965.001.0001/m-en_au-msdict-00001-$1',
['P12724'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780195584516.001.0001/m-en_nz-msdict-00001-$1',
['P11481'] = 'https://greensdictofslang.com/entry/$1',
['P12448'] = 'https://www.daredictionary.com/view/dare/$1',
['P11130'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P11263'] = 'https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fwww.britannica.com%2Fdictionary%2F%251&exp=%28.%2A%29&id=$1',
['P13163'] = 'https://ahdictionary.com/word/search.html?id=$1',
-- Q188 (German)
['P11519'] = 'https://www.owid.de/artikel/$1',
['P11520'] = 'https://www.owid.de/artikel/$1',
['P11521'] = 'https://www.owid.de/artikel/$1',
['P11522'] = 'https://www.owid.de/artikel/$1',
['P11523'] = 'https://www.owid.de/artikel/$1',
['P11524'] = 'https://www.owid.de/artikel/$1',
['P8376'] = 'https://www.duden.de/rechtschreibung/$1',
['P9384'] = 'https://www.woerterbuchnetz.de/Adelung?lemid=$1',
['P9385'] = 'https://www.woerterbuchnetz.de/DWB?lemid=$1',
['P9386'] = 'https://www.woerterbuchnetz.de/DWB2?lemid=$1',
['P9387'] = 'https://www.woerterbuchnetz.de/GWB?lemid=$1',
['P9388'] = 'https://www.woerterbuchnetz.de/Meyers?lemid=$1',
['P9389'] = 'https://www.woerterbuchnetz.de/RDWB1?lemid=$1',
['P9390'] = 'https://www.woerterbuchnetz.de/Wander?lemid=$1',
['P9940'] = 'https://www.dwds.de/wb/$1',
-- Q9035 (Danish)
['P10830'] = 'https://ordregister.dk/id/$1',
['P10831'] = 'https://ordregister.dk/id/$1',
['P9529'] = 'https://ordnet.dk/ddo/ordbog?query=wd&entry_id=$1',
['P9530'] = 'https://ordnet.dk/ddo/ordbog?query=wd&mselect=$1',
['P12828'] = 'https://iserasuaat.gl/daka/daka?f=lo&l=1&p=$1',
['P9962'] = 'https://ordnet.dk/ods/ordbog?query=wd&entry_id=$1',
-- Q25167 (Norwegian Bokmål)
['P10042'] = 'https://ordbøkene.no/bm/$1',
['P9958'] = 'https://naob.no/ordbok/$1',
-- Q25164 (Norwegian Nynorsk)
['P10041'] = 'https://ordbøkene.no/nn/$1',
-- Q652 (Italian)
['P12826'] = 'https://api.tommaseobellini.it/api/text?delta=0&html=true&id=$1',
['P12825'] = 'http://tlio.ovi.cnr.it/voci/$1.htm',
['P5844'] = 'https://www.treccani.it/vocabolario/$1',
['P12420'] = 'https://dizionario.internazionale.it/parola/',
['P12862'] = 'https://www.dizionario.rai.it/p.aspx?nID=lemma&lID=$1',
['P12885'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739569.001.0001/b-it-en-00002-$1',
-- Q1321 (Spanish)
['P12529'] = 'https://wikidata-externalid-url.toolforge.org/?p=12529&url_prefix=https://dle.rae.es/?id=&id=$1',
['P12821'] = 'https://www.oxfordreference.com/display/10.1093/acref/9780191739538.001.0001/b-es-en-00008-$1',
['P12630'] = 'https://aragonario.aragon.es/words/$1',
-- Q9027 (Swedish)
['P8478'] = 'https://www.saob.se/artikel/?unik=$1',
['P9837'] = 'https://svenska.se/so/?id=$1',
['P11838'] = 'https://svenska.se/saol/?id=$1',
-- Q9072 (Finnish)
['P12032'] = 'https://kaino.kotus.fi/fo/?p=article&fo_id=FO_$1',
-- Q8752 (Basque)
['P6838'] = 'https://hiztegiak.elhuyar.eus/eu/$1',
}
return config
0cri709ssqa66b04niwcis25zg0j0fa