Модуль:Источники по теме
Документация
Подгружает ссылки на энциклопедии и братские википроекты из Викиданных и параметров шаблона-шапки и интерпретирует их, показывая в шапках статей.
Используется в Модуль:Отексте, Шаблон:Отексте, Модуль:Обавторе, Шаблон:Обавторе.
Использует:
- MediaWiki:Wikiprojects settings.json — настройки наименований википроектов.
- MediaWiki:Encyclopedias settings.json — настройки заголовков энциклопедий и их id в Викиданных.
- MediaWiki:Encyclopedias sites.json — настройки энциклопедий на внешних сайтах.
Подмодули:
- Модуль:Данные страницы — объект page, в который собираются данные по странице
- Модуль:Источники по теме/wikidata — сборщик данных из Викиданных
- Модуль:Источники по теме/Категоризация — выполняется на последнем этапе, работает по собранным и сортированным данным
- Модуль:Util — хелперы
Функции
p.get_data(frame)
— основная
local RU = 'ru'
local WIKISOURCE = 'wikisource'
local RUWIKISOURCE = 'ruwikisource'
-- Приоритет выбора ссылок на интервики. Расставлены примерно по величине размера проекта и числу админов, с приоритетом для европ., и en-de/pl-uk языков. '*' — любая другая другая интервика
local preferredLanguages = { RU, 'en', 'de', 'pl', 'uk', 'fr', 'it', 'es', 'cs', 'pt', 'da', 'sv', 'fi', 'ja', 'zh', 'he', 'ar', '*' }
local p = {}
local util = require("Module:Util")
local wikidata = require("Модуль:Источники по теме/wikidata")
local projects_cfg = util.get_json('MediaWiki:Wikiprojects settings.json')
local encyclopediasData = util.get_json("MediaWiki:Encyclopedias settings.json") -- настройки заголовков энциклопедий и их id в ВД
-- local encyclopedias_sites_cfg = util.get_json("MediaWiki:Encyclopedias sites.json") -- настройки энциклопедий на внеших сайтах
local page = require("Модуль:Данные страницы").page
function page:add_project(project, manual, wd, index)
local d = p.set_priority_links(manual, wd)
if not self.projects[index] then self.projects[index] = { label = self.sitelinks[index].label, id = self.sitelinks[index].id, links = {} } end
table.insert(self.projects[index].links, { project = project, title = d.title, link = d.link, lang = d.lang, manual_link = manual.link, manual_lang = manual.lang, wd_link = wd.link, wd_lang = wd.lang })
end
function page:add_enc(s) table.insert(self.enc_wikilinks, s) end
page.enc_links_raw = {}
-- Приоритет ссылок на википроекты: ручных ссылок или из ВД
function p.set_priority_links(manual, wd)
local data = {}
if manual.link and wd.link then
-- RU ссылки приоритетней из ВД
-- Ручные обычно устарели на 5-10 лет, часто ведут на ошибочные, удалённые статьи или переделанные в неоднозначности
-- Ссылка на интервики из ВД только если нет ручной ссылки. Поскольку ручная ссылка обычно точнее общей, указанной в preferredLanguages
if wd.lang == RU then
data = wd
else
for _, preflang in pairs(preferredLanguages) do
if preflang ~= RU and preflang ~= '*' then
if preflang == wd.link then
data = wd
break
end
end
end
end
if data.link == nil then data = manual end
elseif manual.link then
data = manual
elseif wd.link then
data = wd
end
return data
end
-- сортировка интервик в формате [проект.язык.страница]. Без monolanguage-проектов.
local function reshape_interwiki_by_projects(wikidataInterwiki)
local interwiki_by_projects = {}
for langprojectcode, title in pairs(wikidataInterwiki) do
if title and langprojectcode ~= 'commonswiki' and langprojectcode ~= 'specieswiki' then
for _, project in pairs(projects_cfg) do
if not project.monolanguage then
local project_code = project.project
local lang = string.match(langprojectcode, '^(.*)' .. project_code .. '$')
if is(lang) then
if not interwiki_by_projects[project_code] then interwiki_by_projects[project_code] = {} end
interwiki_by_projects[project_code][lang] = title
break
end
end
end
end
end
return interwiki_by_projects
end
-- заполняет список `page.projects`
local function make_list_projects_links()
local args = page.args
for index, section in ipairs(page.sitelinks) do
local sitelinks = section.data
--mw.logObject(sitelinks,"sitelinks")
local sitelinks_by_projects = reshape_interwiki_by_projects(sitelinks)
for _, project in pairs(projects_cfg) do
local projectCode = project.project -- like 'wikisource'
local prj_code = project.code
local prj_sitelinks = sitelinks_by_projects[projectCode]
local manual = { lang = nil, link = nil, title = nil } -- ссылки из аргумента шаблона
local wd = { lang = nil, link = nil, title = nil } -- ссылка из Викиданных
-- ручная ссылка в параметре шаблона
local value = args[project.arg] -- значение параметра
if is(value) then
local lang, title = string.match(value, '^:?([a-z]+):(.+)') -- ссылка формата ':код_языка:Название' в параметрах
if not title then
lang, title = RU, value
end
if project.monolanguage then
manual.lang, manual.title, manual.link = nil, title, util.make_interlink(prj_code, nil, title)
else
manual.lang, manual.title, manual.link = lang, title, util.make_interlink(prj_code, lang, title)
end
end
-- поиск ссылки в Викиданных
-- моноязычные проекты (Викисклад, Викивиды, Викиданные)
if project.monolanguage then
local title = sitelinks[projectCode]
if projectCode == 'commons' and not title then
title = sitelinks['commonswiki']
end
if title then
wd.title, wd.link = title, util.make_interlink(prj_code, nil, title)
end
-- мультиязычные проекты
elseif prj_sitelinks then
local foundProjectLink = false
-- перебор предпочтительных языков preferredLanguages
for _, preflang in pairs(preferredLanguages) do
if preflang == '*' then
-- языки под '*' в preferredLanguages
for lang, title in pairs(prj_sitelinks) do
if lang then -- and projectCode ~= WIKISOURCE -- ссылки на малоразвитые интерВикитеки не нужны
wd.lang, wd.title, wd.link = lang, title, util.make_interlink(prj_code, lang, title)
foundProjectLink = true
break
end
end
else
-- языки не под '*' в preferredLanguages
local lang = preflang
local title = prj_sitelinks[lang]
if title then
wd.lang, wd.title, wd.link = lang, title, util.make_interlink(prj_code, lang, title)
foundProjectLink = true
end
end
if foundProjectLink then break end
end
if manual.link and manual.title then
manual.title = mw.ustring.gsub(manual.title, '_', ' ')
end
end
if manual.link or wd.link then
page:add_project(project, manual, wd, index)
elseif projectCode == 'wiki' then
-- если нет ссылок на Википедию, то ссылка на Википедию по параметру ПОИСК
local searchString = args['ПОИСК'] or page.frame1.args.search
-- mw.logObject(page.projects, "page.projects")
-- mw.logObject(index, "index")
if searchString and #searchString > 0 then
manual.link = ':w:Special:Search/' .. searchString
manual.lang = RU
page:add_project(project, manual, wd, index)
end
end
end
end
-- mw.logObject(page, "page")
return page
end
local function getPageTitleFromArgument(enc, title, isPRS)
if enc.project ~= RUWIKISOURCE then
return ':' .. enc.projectCode .. enc.prefix .. title .. enc.suffix
end
local linkVT = nil
local linkDO = nil
if enc.id == "Q1970746" then -- workaround для ручного параметра ТСД=
linkVT = "ТСД/" .. title
linkDO = linkVT .. "/ДО"
else
linkVT = string.gsub(enc.titleVT, "$1", title)
if enc.titleDO then
linkDO = string.gsub(enc.titleDO, "$1", title)
end
end
if isPRS then
if mw.title.new(linkDO, 0).exists then
return linkDO
elseif mw.title.new(linkVT, 0).exists then
return linkVT
else
return linkDO
end
else
if mw.title.new(linkVT, 0).exists then
return linkVT
elseif mw.title.new(linkDO, 0).exists then
return linkDO
else
return linkVT
end
end
end
-- заполняет список `page.enc_wikilinks` викиссылками на энциклопедии
local function make_list_encyclopedias_links(frame)
local args = page.args
local enc_links_raw = page.enc_links_raw
for _, enc in pairs(encyclopediasData) do
local dictArgName = enc.argument
local id = enc.id
local is_title_matches_enc_link = (enc.project == RUWIKISOURCE and (wikidata.is_match_pagenames(page.title, enc.titleVT) or (enc.titleDO and wikidata.is_match_pagenames(page.title, enc.titleDO))))
if not is_title_matches_enc_link then -- исключение страниц энциклопедий идентичных ссылке. TODO: Возможно это дублирует схожий метод из подмодуля ../wikidata : sitlinks[entity.id] = nil -- исключить id базовой энциклопедии
local manual_links, wd_links = {}, {}
-- ссылки из Викиданных
local ids = page.encyclopedias_ids[dictArgName]
if ids then
for _, eid in pairs(ids) do
local link = wikidata.getLink(enc, eid, page.isPRS)
if link then
table.insert(wd_links, link)
end
end
end
-- ссылки из параметров шаблона
local value = args[dictArgName]
if is(value) then
for elem in mw.text.gsplit(value, '%s*~%s*') do -- несколько значений в одном параметре
local link = getPageTitleFromArgument(enc, elem, page.isPRS)
table.insert(manual_links, link)
end
end
-- добавление ссылок
if #manual_links > 0 or #wd_links > 0 then
-- сырые ссылки, разделённые по источникам, используются ниже и для категоризации
enc_links_raw[dictArgName] = { manual_links = manual_links, wd_links = wd_links, enc = enc }
-- викификация и фильтрация ссылок
-- любые из шаблона, могут включать ссылки с якорями #
for _, mlink in pairs(manual_links) do
page:add_enc(util.make_wikilink(mlink, enc.title))
end
-- из Викиданных, исключая дубли шаблонных ссылок и содержащие #
for _, wlink in pairs(wd_links) do
local wlink_eq_mlink = false
for _, mlink in pairs(manual_links) do
if mlink == wlink or mw.ustring.match(mlink, '^(.+)#') then
wlink_eq_mlink = true
break
end
end
if not wlink_eq_mlink then
page:add_enc(util.make_wikilink(wlink, enc.title))
end
end
end
end
end
-- внешние сайты
for enc_name, site in pairs(page.external_sites) do
page:add_enc(site.wikilink)
end
-- mw.logObject(page, "page")
return page
end
function p.get_data(frame)
page:init(frame)
page = wikidata.get_links(page)
-- mw.logObject(page, "page")
make_list_projects_links()
p.render_projects_links()
make_list_encyclopedias_links()
if page.is_author_page then
-- рендеринг тега для отображения размещён в [[Модуль:Обавторе]]
else
p.renderEncyclopedias_aboutText()
end
page = require("Модуль:Источники по теме/Категоризация").get_categories(page)
--mw.logObject(page.projects, "page.projects")
return page
end
-- оформление меню со ссылками, как html в виде строки, для {{отексте}} и Модуль:Отексте
function p.render_projects_links()
local sources = page.projects
-- mw.logObject(page.projects, "page.projects")
local menu = ''
if #sources > 0 then
for i, w in ipairs(sources) do
local links = {}
local prefix = '<li class="submenu-label">' .. w.label .. '<ul>'
local suffix = '</ul></li>'
if #sources == 1 then prefix, suffix = '', '' end
for _, v in pairs(w.links) do
local project, link, lang, title = v.project, v.link, v.lang, v.title
local is_recursive_link = page.title == title and lang == RU and project.project == WIKISOURCE
if link and not is_recursive_link then
local b = ""; if project.project == "wikidata" then b = "'''" end
local prj_title = ''; if page.isPRS then prj_title = project.titlePRS else prj_title = project.title end
local lang_label = ''; if lang and lang ~= RU then lang_label = " <sup><small>(" .. lang .. ")</small></sup>" end
table.insert(links, '<li class="menu-wiki-'..project.project..'"><span class="about-extlink">' .. b .. "[[Файл:" .. project.logo .. "|13px|link=]] [[" .. link .. "|" .. prj_title .. "]]" .. b .. lang_label .. '</span></li>')
end
end
if #links > 0 then
menu = menu .. prefix .. table.concat(links, '\n') .. suffix
end
end
end
-- mw.logObject(menu, "menu")
if is(menu) then menu = '<li id="menu-wiki">' .. "'''Википроекты'''<ul>" .. menu .. '</ul></li>' end
page.projects_links_rendered = menu
return menu
end
-- оформление меню со ссылками, как html в виде строки, для шапки {{отексте}}, вызывается из Модуль:Отексте
function p.renderEncyclopedias_aboutText()
local menu = ''
local wikilinks = page.enc_wikilinks
if #wikilinks > 0 then
local _links = {}; for _, v in pairs(wikilinks) do table.insert(_links, "<li>" .. v .. "</li>") end
local links = table.concat(_links, '\n')
-- разделители
local hr = "<hr style='width:100%%'>"
local pre = "<div class=flexsep style='display:flex;justify-content:center;align-items:center;user-select:none'>" .. hr .. "<span style='font-size:smaller;padding:0 5px'>"
local post = "</span>" .. hr .. "</div>"
local otherlang, external = pre .. "на других языках" .. post, pre .. "внешние ссылки" .. post
links = links:gsub( "(<li>%[%[:)", "<li class=lisep>" .. otherlang .. "</li>\n%1", 1 )
links = links:gsub( "(<li>%[http)", "<li class=lisep>" .. external .. "</li>\n%1", 1 )
local desc; if page.isPRS then desc = 'Энциклопедіи' else desc = 'Энциклопедии' end
menu = '<li id="menu-dicts">' .. "'''" .. desc .. "'''<ul>" .. links .. '</ul></li>'
end
page.enc_links_rendered = menu
-- mw.logObject(menu,"menu")
return menu
end
-- проверка переменной, возврат её или nil если пустая
function is(var) if (var == '' or var == nil) then return nil else return var end end
return p