Модуль:Другие источники
Перейти к навигации
Перейти к поиску
Для документации этого модуля может быть создана страница Модуль:Другие источники/doc
local currentProject = 'ruwikisource'
local wd = require("Module:WD")
local is_author_page
local encyclopediasData = mw.text.jsonDecode(
mw.title.new( "MediaWiki:Encyclopedias settings.json" ):getContent()
) -- настройки заголовков энциклопедий и их id в ВД
local function getClaimValues( entity, propertyId )
local result = {}
local claim = entity.claims[ propertyId ]
if ( claim == nil ) then
return result
end
for _, statement in pairs( claim ) do
local mainsnak = statement.mainsnak
if ( mainsnak ~= nil and mainsnak.datavalue ~= nil ) then
if ( mainsnak.datavalue.type == "string" ) then
result[#result+1] = mainsnak.datavalue.value
elseif ( mainsnak.datavalue.type == "wikibase-entityid" ) then
result[#result+1] = 'Q' .. mainsnak.datavalue.value["numeric-id"]
else
result[#result+1] = mainsnak.datavalue.value
end
end
end
return result
end
local function getQualifierValues( statement, qualifierName )
local result = {}
if (statement ~= nil
and statement.qualifiers ~= nil
and statement.qualifiers[qualifierName] ~= nil) then
local qualifiers = statement.qualifiers[qualifierName]
for _, qualifier in pairs( qualifiers ) do
if (qualifier.datavalue ~= nil
and qualifier.datavalue.type ~= nil
and qualifier.datavalue.value ~= nil) then
if ( qualifier.datavalue.type == "wikibase-entityid" ) then
result[#result+1] = 'Q' .. qualifier.datavalue.value["numeric-id"]
end
end
end
end
return result
end
local p = {}
local is_topic_property = false -- для установки категории при наличии P921
function p.populateEncyclopediasDataByEntityId( 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.populateEncyclopediasDataByEntity( entity, result )
end
function p.populateEncyclopediasDataByEntity( entity, result )
if ( result == nil ) then
result = {}
end
if ( entity == nil or entity.claims == nil ) then
return result
end
-- first check current item references
local describedByClaim = entity.claims[ 'P1343' ]
if ( describedByClaim ~= nil ) then
for _, statement in pairs( describedByClaim ) do
if ( statement.mainsnak ~= nil
and statement.rank ~= 'deprecated'
and statement.mainsnak.datavalue.type == "wikibase-entityid"
and statement.mainsnak.datavalue.value["numeric-id"] ~= nil ) then
local dictId = 'Q' .. statement.mainsnak.datavalue.value["numeric-id"]
for _, enc in pairs( encyclopediasData ) do
local dictionaryShortTitle = enc.argument
local dictinaryEntityId = enc.id
if ( dictinaryEntityId == dictId ) then
local qualifiers = getQualifierValues(statement, 'P805') -- P805 тема утверждения
if (qualifiers == nil or #qualifiers == 0) then
qualifiers = getQualifierValues(statement, 'P248') -- P248 утверждается в (deprecated)
end
for _, qualifierValue in pairs( qualifiers ) do
local dictLinks = result[ dictionaryShortTitle ]
if ( dictLinks == nil ) then
dictLinks = {}
result[ dictionaryShortTitle ] = dictLinks
end
dictLinks[ qualifierValue ] = qualifierValue
end
end
end
end
end
end
-- check if entity have main topic item
-- для энциклопедических, словарных статей и перенаправлений (P31 in [Q10389811, Q13433827, Q1580166, Q1302249]) просматриваем P921 ("основная тема произведения")
if ( entity ) then
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) then
local parentEntityIds = getClaimValues( entity, 'P921' )
--mw.logObject(parentEntityIds,"parentEntityIds")
for _, parentEntityId in pairs( parentEntityIds ) do
is_topic_property = true
p.populateEncyclopediasDataByEntityId( parentEntityId, result )
end
end
end
-- check if entity have edition of item
if ( entity ) then
local parentEntityIds = getClaimValues( entity, 'P629' )
for _, parentEntityId in pairs( parentEntityIds ) do
p.populateEncyclopediasDataByEntityId( parentEntityId, result )
end
end
return result
end
--[[
parseLink("ЭСБЕ/Пупкин, Иван Васильевич/ДО", "ЭСБЕ/$1/ДО") → "Пупкин, Иван Васильевич"
parseLink("ЭСБЕ/Пупкин, Иван Васильевич", "ЭСБЕ/$1/ДО") → nil
]]
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", "(.+)").."$"
-- mw.log("regexp: "..s_regexp)
return string.match(s_sitelink, s_regexp)
-- for s_catch in string.match(s_sitelink, s_regexp) do
-- return s_catch
-- end
-- return nil
end
--[[
{{#invoke:Другие источники|test_parseLink|ЭСБЕ/Пупкин, Иван Васильевич/ДО|ЭСБЕ/$1/ДО}} → "Пупкин, Иван Васильевич"
{{#invoke:Другие источники|test_parseLink|МЭСБЕ/Аконит|МЭСБЕ/$1}} → "Аконит"
{{#invoke:Другие источники|test_parseLink|ЭСБЕ/Аконит|МЭСБЕ/$1}} → nil
]]
function p.test_parseLink(frame)
local s_sitelink = tostring(frame.args[1])
local s_pattern = tostring(frame.args[2])
local s_title = parseLink(s_sitelink, s_pattern)
if s_title == nil then
return "nil"
else
return '"'..s_title..'"'
end
end
local function getLink( enc, entityId, isPRS )
if enc.project ~= currentProject then
local entity = mw.wikibase.getEntity( entityId )
if not entity then
mw.log("Невозможно загрузить "..tostring(entityId))
return nil
end
if (entity.sitelinks == nil) or (entity.sitelinks[enc.project] == nil) then
mw.log("В "..tostring(entityId).." нет ссылки на "..enc.project.." для "..enc.argument)
return nil
end
return ':' .. enc.projectCode .. entity.sitelinks[enc.project].title
end
local s_sitelink = mw.wikibase.sitelink(entityId)
if s_sitelink == nil then
return nil
end
local s_primary_pattern = nil
local s_secondary_pattern = nil
if isPRS then
s_primary_pattern = enc.titleDO
s_secondary_pattern = enc.titleVT
else
s_primary_pattern = enc.titleVT
s_secondary_pattern = enc.titleDO
end
mw.log(isPRS,s_primary_pattern,s_secondary_pattern,s_sitelink)
if parseLink(s_sitelink, s_primary_pattern) ~= nil then -- ссылка из Викиданных соответствует признаку isPRS
return s_sitelink -- т.к. ссылка получена из Викиданных, поверять её существование не надо, просто её возвращаем
end
-- Т.к. ссылка из Викиданных не соответсвует признаку isPRS,
-- попробуем возвратить "правильную" ссылку (если она существует, конечно)
local s_article_title
if enc.titleDO then
s_article_title = parseLink(s_sitelink, s_secondary_pattern)
end
if s_article_title == nil then
-- ссылка не соответсвует ни titleDO, ни titleVT
-- это какая-то ошибка, выводим сообщение на консоль и возвращаем её
mw.log("ссылка на "..enc.title.." нарушает правила именования: "..s_sitelink)
return s_sitelink
end
local s_link
if enc.id == "Q1970746" then -- workaround для ТСД
s_link = "ТСД/"..s_article_title
if isPRS then
s_link = s_link.."/ДО"
end
else
s_link = string.gsub(s_primary_pattern, "$1", s_article_title)
end
if mw.title.new(s_link, 0).exists then
return s_link
else
return s_sitelink
end
end
local function isNotBlank( str )
return str ~= nil and mw.ustring.len( str ) > 0
end
local function getPageTitleFromArgument( enc, title, isPRS )
if ( enc.project ~= currentProject ) 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
local function getDefaultTitle( title )
for _, enc in pairs( encyclopediasData ) do
if (enc.project == currentProject) and enc.titleDO then
local DO = (enc.default == 'DO')
local titleVT, titleDO = enc.titleVT, enc.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
local function fetchEncyclopediasLinks( frame )
local data = { wlinks={}, categories={}, categories_raw={}, isPRS }
function data:add(s) table.insert(self.wlinks, s) end
function data:add_category(s)
table.insert(self.categories, '[[Категория:'..s..']]')
table.insert(self.categories_raw, s)
end
data.isPRS = frame.isPRS
local args = frame:getParent().args
local page_title = mw.title.getCurrentTitle().text
local wd_entity = mw.wikibase.getEntity()
if not wd_entity then
local default_title = getDefaultTitle( page_title )
wd_entity = mw.wikibase.getEntity(mw.wikibase.getEntityIdForTitle(default_title))
end
local encyclopediasIds = p.populateEncyclopediasDataByEntity( wd_entity, nil )
-- проверка обратной ссылки («описывается в источниках»)
if wd_entity
and (wd.has_valid_item_value (wd_entity, "P31", 10389811)
or wd.has_valid_item_value (wd_entity, "P31", 13433827)
or wd.has_valid_item_value (wd_entity, "P31", 1580166))
and wd_entity.claims.P921 then
--mw.logObject(wd_entity, "wd_entity")
--local has_backlink
for _, sub in pairs(wd_entity.claims.P921) do
local dv = sub.mainsnak.datavalue
if type(dv) == "table" and type(dv.value) == "table" and dv.value.id then
local has_backlink
local sub_entity = mw.wikibase.getEntity (dv.value.id)
if sub_entity and sub_entity.claims and sub_entity.claims.P1343 then
--mw.logObject(sub_entity.claims.P1343, "sub_entity.claims.P1343")
for _, refs in pairs(sub_entity.claims.P1343) do
if refs.qualifiers and refs.qualifiers.P805 then
for _, ref in pairs(refs.qualifiers.P805) do
if ref.datavalue and ref.datavalue.value and ref.datavalue.value.id then
local ref_id = ref.datavalue.value.id
if ref_id == wd_entity.id then has_backlink = true break end
end
end
if has_backlink then break end
end
end
end
if not has_backlink then data:add_category('Викиданные:Страницы с указанным элементом темы без обратной ссылки') end
end
end
--[[for i, v in pairs(encyclopediasIds) do
if v[wd_entity.id] then has_backlink = true break end
end
if not has_backlink then data:add_category('Викиданные:Страницы с указанным элементом темы без обратной ссылки') end]]
end
for _, enc in pairs( encyclopediasData ) do
local dictArgName = enc.argument
local id = enc.id
if not ((enc.project == currentProject) and (parseLink(page_title, enc.titleVT) ~= nil or (enc.titleDO and parseLink(page_title, enc.titleDO) ~= nil))) then
local s_param_value = args[dictArgName]
local ids = encyclopediasIds[dictArgName]
local manual_link, wd_link
local mlinks, wdlinks = {}, {}
if isNotBlank(s_param_value) then
-- local keyword to suppress WD output
if s_param_value then
for elem in mw.text.gsplit( s_param_value, '%s*~%s*' ) do -- несколько значений в одном параметре
manual_link = getPageTitleFromArgument( enc, elem, data.isPRS )
table.insert(mlinks, manual_link)
end
data:add_category('Ручная ссылка:' .. dictArgName)
end
end
if ids ~= nil then
for _, id in pairs(ids) do
wd_link = getLink(enc, id, data.isPRS)
if wd_link == nil then
-- элемент без страницы на искомом языке, пропускаем
else
table.insert(wdlinks, wd_link)
data:add_category('Ссылка из Викиданных:' .. dictArgName)
end
end
end
-- добавление ссылок
for _, manual_link in pairs(mlinks) do
data:add( '[[' .. manual_link .. '|' .. enc.title .. ']]')
if not enc.projectCode and not mw.title.new( manual_link ).exists then
data:add_category('Ручная ссылка на несуществующую словарную статью:' .. dictArgName)
end
end
-- добавлять ссылки из ВД которые не дублируют ручные
for _, wd_link in pairs(wdlinks) do
if #mlinks>0 then
for _, manual_link in pairs(mlinks) do
if wd_link ~= manual_link then
local link
if mw.ustring.match( manual_link, '^(.+)#') then
data:add_category('Якорь в ручной ссылке')
else
data:add( '[[' .. wd_link .. '|' .. enc.title .. ']]')
end
end
end
else
data:add( '[[' .. wd_link .. '|' .. enc.title .. ']]')
end
end
for _, manual_link in pairs(mlinks) do
for _, wd_link in pairs(wdlinks) do
if wd_link == manual_link then
data:add_category('Ручная ссылка совпадает со ссылкой из Викиданных:' .. dictArgName)
end
end
end
end
end
if not is_author_page then
if wd_entity then
data:add_category('Викиданные:Страницы с элементами|'..page_title)
if is_topic_property then data:add_category('Викиданные:Страницы с указанным элементом темы|'..page_title)
else data:add_category('Викиданные:Страницы с элементами без указания элемента темы|'..page_title) end
end
end
-- mw.logObject(data, "data")
return data
end
function p.fetchEncyclopediasLinks( frame, _is_author_page )
is_author_page = _is_author_page
return fetchEncyclopediasLinks(frame )
end
-- оформление ссылок для шапки {{отексте}}, вызывается из Модуль:Отексте
function p.renderOtherSources_aboutText( frame )
local data = fetchEncyclopediasLinks(frame)
local result = ''
if #data.wlinks >0 then
local desc; if frame.isPRS then desc = 'Другіе источники' else desc = 'Другие источники' end
result = " • '''"..desc.."''': " .. table.concat(data.wlinks, ' : ')
end
-- mw.logObject(result, "result")
return result .. table.concat(data.categories)
end
return p