Модуль:Навигация-мини
Перейти к навигации
Перейти к поиску
Для документации этого модуля может быть создана страница Модуль:Навигация-мини/doc
local p = {}
local wd = require("Module:WD")
local is_author_page
local RU = 'ru'
local WIKISOURCE = 'wikisource'
local RUWIKISOURCE = 'ruwikisource'
local argSearch = 'ПОИСК'
-- Приоритет выбора ссылок на интервики. Расставлены примерно по величине размера проекта и числу админов, с приоритетом для европ., и en-de/pl-uk языков. '*' — любая другая другая интервика
local preferredLanguages = { RU, 'en', 'de', 'pl', 'uk', 'fr', 'it', 'es', 'cs', 'pt', 'da', 'sv', 'fi', 'ja', 'zh', 'he', 'ar', '*' }
-- Настройки наименований википроектов
local projects = mw.text.jsonDecode( mw.title.new( 'MediaWiki:Wikiprojects settings.json' ):getContent())
local parentProperties = {
-- 'P921', -- main topic link
-- 'P910', -- main category. Отключено. В ссылках на интервики проектов (ВП, ВТ итп) выводит интервики категорий.
-- Напр., [[ЕЭБЕ/Ассирия]] → item → item main topic → item main category → get interwiki category
-- 'P629', -- edition or translation of
-- 'P361', -- part of
}
-- local currentTitleFull = mw.title.getCurrentTitle().fullText
--[[
Функция возвращает массив значений свойства propertyId из элемента entity
Возвращаются значения "preferred", если они есть, иначе значения "normal".
]]
local function getClaimValues( entity, propertyId )
local result = {}
local claim = nil
if entity ~= nil and entity.claims ~= nil then
claim = entity.claims[ propertyId ]
end
if claim ~= nil then
local b_prefered_mode = false
for key, value in pairs(claim) do
local snak = nil
if value.rank == "preferred" then -- предпочтительный ранг
if not b_prefered_mode then
result = {}
b_prefered_mode = true
end
snak = value.mainsnak
elseif value.rank == "normal" and not b_prefered_mode then -- обычный ранг
snak = value.mainsnak
end
if snak ~= nil and snak.snaktype == "value" then
if snak.datavalue.type == "wikibase-entityid" then
result[#result+1] = "Q" .. snak.datavalue.value["numeric-id"]
else
result[#result+1] = snak.datavalue.value
end
end
end
end
return result
end
--[[
-- функция для тестирования
-- {{#invoke:Навигация-мини|test_getClaimValues|Q20646238|P921}}
function p.test_getClaimValues (frame)
local s_item = frame.args[1]
local s_property = frame.args[2]
local entity = mw.wikibase.getEntity(s_item)
local data = getClaimValues(entity, s_property)
local s_result = ""
for key, value in pairs(data) do
s_result = s_result .. "[" .. key .. "]: " .. tostring(value) .. "<br/>"
end
return s_result
end
]]
--[[
function p.populateInterwikiByEntityId( entityId, result )
if result == nil then
result = {}
end
if entityId == nil then
return result
end
local entity = mw.wikibase.getEntity( entityId )
if entity == nil then
return result
end
return p.populateInterwikiByEntity( entity, result )
end
]]
function p.populateInterwikiByEntity(entity, result)
-- populate from entity interwiki
local sitelinks = entity.sitelinks
if sitelinks ~= nil then
for sitecode, sitelink in pairs( sitelinks ) do
-- mw.log(" "..sitecode.." = "..sitelink.title)
if result[sitecode] == nil then
result[sitecode] = sitelink.title
end
end
end
-- check if entity have main topic item
-- ToDo: блок не используется, 'P921' (main topic link) просматривается в populate_interwikis_from_item()
for _, propertyCode in pairs( parentProperties ) do
local parentEntityIds = getClaimValues( entity, propertyCode )
for _, parentEntityId in pairs( parentEntityIds ) do
local entity2 = mw.wikibase.getEntity(parentEntityId)
-- if propertyCode == 'P921' and result['wikidata'] == nil then
-- result['wikidata'] = entity2.id -- entity itself is a wikidata link
-- end
p.populateInterwikiByEntity(entity2, result)
end
end
if result['commons'] == nil then
local commonsCategories = getClaimValues( entity, 'P373' )
for _, commonsCategory in pairs( commonsCategories ) do
result[ 'commons' ] = 'Category:' .. commonsCategory
break
end
-- если commons нет в интервиках и в P373, то использовать изображение из P18
if result[ 'commons' ] == nil then
local commonsCategories = getClaimValues( entity, 'P18' )
for _, commonsCategory in pairs( commonsCategories ) do
result[ 'commons' ] = 'File:' .. commonsCategory
break
end
end
end
return result
end
local function parseLink(s_sitelink, s_pattern)
local s_regexp = string.gsub(s_pattern, "%(", "%%(");
s_regexp = string.gsub(s_regexp, "%)", "%%)");
s_regexp = "^"..string.gsub(s_regexp, "$1", "(.+)").."$";
return string.match(s_sitelink, s_regexp);
end
local function getDefaultTitle()
local otherSources = mw.text.jsonDecode(mw.title.new( "MediaWiki:Encyclopedias settings.json" ):getContent())
local title = mw.title.getCurrentTitle().text;
for _, sourceDescription in pairs( otherSources ) do
if (sourceDescription.project == 'ruwikisource') and sourceDescription.titleDO then
local DO = (sourceDescription.default == 'DO')
local titleVT, titleDO = sourceDescription.titleVT, sourceDescription.titleDO
local nameVT, nameDO = parseLink( title, titleVT ), parseLink( title, titleDO )
if nameDO then
if DO then return titleDO:gsub( '$1', nameDO ) else return titleVT:gsub( '$1', nameDO ) end
elseif nameVT then
if DO then return titleDO:gsub( '$1', nameVT ) else return titleVT:gsub( '$1', nameVT ) end
end
end
end
return title
end
-- загрузка списка интервик из элемента текущей страницы
function populate_interwikis_from_item( manual_topic_id )
if manual_topic_id == '' then manual_topic_id = nil end
local entity = mw.wikibase.getEntity()
if not entity then
local default_title = getDefaultTitle()
entity = mw.wikibase.getEntity(mw.wikibase.getEntityIdForTitle(default_title))
end
local wikidataInterwiki = {}
if entity ~= nil then
-- для энциклопедических, словарных статей и перенаправлений (P31 in [Q10389811, Q13433827, Q1580166, Q1302249]) просматриваем P921 ("основная тема произведения")
if wd.has_valid_item_value (entity, "P31", 10389811)
or wd.has_valid_item_value (entity, "P31", 13433827)
or wd.has_valid_item_value (entity, "P31", 1580166)
or wd.has_valid_item_value (entity, "P31", 1302249)
or wd.has_valid_item_value (entity, "P31", 7725634) -- литературное произведение
then
local topics = getClaimValues(entity, "P921")
for key, item_id in pairs(topics) do
-- mw.log("просматриваем: "..item_id)
if wikidataInterwiki['wikidata'] == nil then
wikidataInterwiki['wikidata'] = item_id
end
local topic_item = mw.wikibase.getEntity(item_id)
wikidataInterwiki = p.populateInterwikiByEntity(topic_item, wikidataInterwiki)
end
if manual_topic_id and #topics == 0 then
local topic_item = mw.wikibase.getEntity(manual_topic_id)
wikidataInterwiki = p.populateInterwikiByEntity(topic_item, wikidataInterwiki)
end
else
-- mw.log("это не энциклопедическая статья")
wikidataInterwiki['wikidata'] = entity.id
wikidataInterwiki = p.populateInterwikiByEntity(entity, wikidataInterwiki)
if wikidataInterwiki[RUWIKISOURCE] == mw.title.getCurrentTitle().fullText then
wikidataInterwiki[RUWIKISOURCE] = nil
end
end
elseif manual_topic_id then
local topic_item = mw.wikibase.getEntity(manual_topic_id)
wikidataInterwiki = p.populateInterwikiByEntity(topic_item, wikidataInterwiki)
end
return wikidataInterwiki
end
-- сортировка интервик в формате [проект.язык.страница]. Без monolanguage-проектов.
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 ) do
if not project.monolanguage then
local project_code = project.project
local lang = string.match( langprojectcode, '^(.*)'..project_code..'$' )
if lang and 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
-- сюда собираются данные
local result = {
wlinks = {},
categories = {}, categories_raw = {},
IS_PRS = require( "Module:Header" ).parse_title( mw.title.getCurrentTitle().text , "isPRS" ), -- isDO = isCurrentPageDO()
}
function result:add(project, manual_link, manual_lang, wd_link, wd_lang)
link, lang = set_priority_links(manual_link, manual_lang, wd_link, wd_lang)
table.insert(self.wlinks, {project=project, link=link, lang=lang, manual_link=manual_link, manual_lang=manual_lang, wd_link=wd_link, wd_lang=wd_lang} )
end
function result:add_category(s)
table.insert(self.categories, '[[Категория:'..s..']]')
table.insert(self.categories_raw, s)
end
-- сбор данных
function scrape_data( frame )
local args = frame:getParent().args
local wikidataInterwiki = populate_interwikis_from_item( args['ВИКИДАННЫЕ'] )
local interwiki_by_projects = reshape_interwiki_by_projects( wikidataInterwiki )
-- mw.logObject(interwiki_by_projects, "interwiki_by_projects")
for _, project in pairs( projects ) do
local projectCode = project.project -- like 'wikisource'
local prj_arg = project.arg
local prj_code = project.code
local prj_name = project.name
local manual_link, wd_link
local manual_lang, wd_lang
local manual_title, wd_title
local interwikis = interwiki_by_projects[ projectCode ]
repeat
-- ручная ссылка в параметре шаблона
local value = args[prj_arg] -- значение параметра
if value and #value > 0 then
if value ~= '__NULL__' then
local lang, title = string.match( value, '^:?([a-z]+):(.+)' ) -- ссылка формата ':код языка:Название'
if lang then
manual_link = prj_code .. ':' .. lang .. ':' .. title
manual_lang = lang
manual_title = title
else
manual_lang = RU
manual_title = value
if projectCode == WIKISOURCE then
manual_link = value
else
manual_link = prj_code .. ':' .. value
end
end
result:add_category('Ручная ссылка:' .. prj_name)
end
end
-- поиск ссылки в Викиданных
-- моноязычные проекты (Викисклад, Викивиды, Викиданные)
if project.monolanguage then
-- При projectCode == "wikidata":
-- - для энциклопедических статей категория "Ссылка из Викиданных" ставится по property P921 ("основная тема")
-- - для других страниц - если Викитека указана в списке проектов
local title = wikidataInterwiki[ projectCode ]
if projectCode == 'commons' and not title then
title = wikidataInterwiki[ 'commonswiki' ]
end
if title then
wd_link = prj_code .. ':' .. title
wd_title = title
result:add_category('Ссылка из Викиданных:' .. prj_name)
-- elseif projectCode == 'commons' then
-- 'P373'
end
-- мультиязычные проекты
elseif interwikis then
-- mw.logObject(interwikis, "interwikis")
local foundProjectLink = false
-- перебор предпочтительных языков preferredLanguages
for _, preflang in pairs( preferredLanguages ) do
if preflang == '*' then
-- языки под '*' в preferredLanguages
for lang, title in pairs( interwikis ) do
if lang then -- and projectCode ~= WIKISOURCE -- ссылки на малоразвитые интерВикитеки не нужны
wd_link = prj_code .. ':' .. lang .. ':' .. title
wd_lang = lang
wd_title = title
result:add_category('Ссылка из Викиданных на интервики:' .. prj_name)
foundProjectLink = true
break
end
end
else
-- языки не под '*' в preferredLanguages
local lang = preflang
local title = interwikis[ lang ]
if title then
if lang == RU then
if projectCode == WIKISOURCE then
wd_link = ':' .. title
else
wd_link = prj_code .. ':' .. title
end
if not manual_link and not (is_author_page and projectCode == WIKISOURCE) then
result:add_category('Ссылка из Викиданных:' .. prj_name)
end
else
if projectCode == WIKISOURCE then
wd_link = ':' .. lang .. ':' .. title
else
wd_link = prj_code .. ':' .. lang .. ':' .. title
end
if not manual_link and not (is_author_page and projectCode == WIKISOURCE) then
result:add_category('Ссылка из Викиданных на интервики:' .. prj_name .. ':язык:' .. lang)
end
end
wd_lang = lang
wd_title = title
foundProjectLink = true
end
end
if foundProjectLink then break end
end
if manual_link and manual_title then
-- категоризация: есть ли ручная ссылка в интервиках ВД
local is_manual_link_in_wd
manual_title = mw.ustring.gsub(manual_title, '_', ' ')
for lang, title in pairs( interwikis ) do
if lang == manual_lang and title == manual_title then
is_manual_link_in_wd = true
result:add_category('Ручная ссылка совпадает со ссылкой из Викиданных:'..prj_name)
break
end
end
if not is_manual_link_in_wd then
result:add_category('Ручная ссылка отличается от ссылки из Викиданных:'..prj_name)
end
end
end
if not wd_link and not manual_link and projectCode == 'wiki' then
-- если нет ссылок на Википедию
local searchString = args[ argSearch ] or frame.args.search
if searchString and #searchString > 0 then
manual_link = prj_code .. ':Special:Search/' .. searchString
manual_lang = RU
end
end
if manual_link or wd_link then
result:add( project, manual_link, manual_lang, wd_link, wd_lang )
break -- continue to next project
end
until true
end
-- Для страниц авторов категории дальше меняются в Модуль:Обавторе в change_wd_categories()
-- mw.logObject(result, "result")
return result
end
function p.scrape_data( frame , _is_author_page)
is_author_page = _is_author_page
return scrape_data( frame )
end
-- Приоритет ссылок: ручных ссылок или из ВД.
function set_priority_links(manual_link, manual_lang, wd_link, wd_lang)
local link, lang
if manual_link and wd_link then
-- RU ссылки приоритетней из ВД
-- Ручные обычно устарели на 5-10 лет, часто ведут на ошибочные, удалённые статьи или переделанные в неоднозначности
if wd_lang == RU then
link, lang = wd_link, wd_lang
-- Ссылка на интервики из ВД только если нет ручной ссылки. Поскольку ручная ссылка обычно точнее общей, указанной в preferredLanguages
else
for _, preflang in pairs( preferredLanguages ) do
if preflang ~= RU and preflang ~= '*' then
if preflang == wd_link then
link, lang = wd_link, wd_lang
break
end
end
end
end
if link == nil then link, lang = manual_link, manual_lang end
elseif manual_link then
link, lang = manual_link, manual_lang
elseif wd_link then
link, lang = wd_link, wd_lang
end
return link, lang
end
-- оформление строки для {{отексте}} и Модуль:Отексте
function p.render( frame )
local dataset = scrape_data( frame )
if #dataset.wlinks > 0 then
local links = {}
for _, v in pairs(dataset.wlinks) do
local project, link, lang = v.project, v.link, v.lang
if link then
local prj_title = ''; if dataset.IS_PRS 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, '<span class="about-extlink">' .. "[[Файл:"..project.logo.."|13px|link=]] [["..link.."|"..prj_title.."]]" .. lang_label .. '</span>')
end
end
local result = ''
if #links > 0 then
links = table.concat(links, ' ')
result = " <div style=\"float:right;\">'''Википроекты:''' "..links..'</div>'
end
if #dataset.categories > 0 then result = result .. table.concat(dataset.categories) end
return result
end
end
return p