Module:Interwiki

Revision as of 10:36, 22 November 2020 by PeaceDeadC (talk | contribs) (Created page with "--[[ __ __ _ _ ___ _ _ _ _ | \/ | ___ __| |_ _| | ___ _|_ _|_ __ | |_ ___ _ ____ _(_) | _(_) | |\/| |/ _...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:Interwiki/doc

--[[
  __  __           _       _        ___       _                     _ _    _  
 |  \/  | ___   __| |_   _| | ___ _|_ _|_ __ | |_ ___ _ ____      _(_) | _(_) 
 | |\/| |/ _ \ / _` | | | | |/ _ (_)| || '_ \| __/ _ \ '__\ \ /\ / / | |/ / | 
 | |  | | (_) | (_| | |_| | |  __/_ | || | | | ||  __/ |   \ V  V /| |   <| | 
 |_|  |_|\___/ \__,_|\__,_|_|\___(_)___|_| |_|\__\___|_|    \_/\_/ |_|_|\_\_| 
                                                                              
]]

--------------------------------------------------------------------

-- Properties to use as redirects 
local redirectProperties = { 
	'P50', -- "category's main topic"
	'P512', -- "said to be the same as"
	'P513', -- "taxon synonym"
	'P300' -- "list related to category"
}

-- =======================================
-- === Local Functions ===================
-- =======================================

------------------------------------------------------------------------------
-- Based on frame structure create "args" table with all the input parameters.
-- All inputs are non case-sensitive. Input values are trimmed and empty string a 
-- re converted to nils. 
local function getArgs(frame)
	local function normalize_input_args(input_args, output_args)
		for name, value in pairs( input_args ) do 
			if type(name)=='string' and value ~= '' then 
				output_args[string.lower(name)] = value
			end
		end
		return output_args
	end
	local args = {}
	args = normalize_input_args(frame:getParent().args, args)
	args = normalize_input_args(frame.args, args)
	return args
end

-- convert from a list to a set
local function list2set(list, set) 
	set = set or {}
	for _, v in ipairs(list) do set[v]=true end
	return set
end

--------------------------------------------------------------------
-- Collect one or more item ID from a property
local function getProperty(entity, prop) 
	propVal = {}
	if entity and entity.claims then
		for _, statement in pairs(entity:getBestStatements( prop )) do
			if statement.mainsnak.snaktype == 'value' then
				table.insert(propVal, statement.mainsnak.datavalue.value.id)
			end
		end
	end
	return propVal
end

-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}

--------------------------------------------------------------------
-- Purpose: create old wikitext stype interwiki links (links shown on the left 
-- side of the page) to add or replace interwiki links based on Wikidata 
-- sitelinks
-- Use as follows:
--  * {{#invoke:Interwiki|interwiki}} will examine wikidata item and see if 
--       any "redirectProperties" are present if any are than the first item 
--       ID will be used. We will than proceed to add to interwiki links in
--       addition to the ones based on Wikidata sitelinks 
--  * {{#invoke:Interwiki|interwiki|qid=Q5}} specify an item to draw interwikis from
--  * {{#invoke:Interwiki|interwiki|test=1}} will display interwikilinks as bullet list 
--        to allow debuging
function p.interwiki(frame)
	-- process inputs
	local args = getArgs(frame)
	local qid  = args.qid         -- get uses parameter "qid"  if provided
	local test = args.test or '0' -- get uses parameter "test" if provided
	test = (test=='yes' or test=='y' or test=='true'  or test=='1')    -- convert to boolean
	local fStr = (test and '*[[pbd:%s:%s]]') or '[[%s:%s]]'              -- link format: in normal or in test mode
	
	-- Excludes some wikiprojects that are not Wikipedia, even if their code ends with 'wiki'
	-- The last one is the name of the current project
	local excludedProjects = {'pbc', mw.wikibase.getGlobalSiteId()}	
	excludedProjects = list2set(excludedProjects)  -- convert from a list to a set

	-- current page is connected through a sitelink to an wikidata entity
	local entity = mw.wikibase.getEntity()
	if entity then 
		-- find wikidata item from which to copy interwiki links
		if (not qid or qid == '') then
			for _, prop in ipairs(redirectProperties) do
				qid = getProperty(entity, prop)[1] -- follow wikidata's item redirect-like properties
				if qid then break end
			end
		end
		-- check if we are at category item
		local instanceOf = list2set(getProperty(entity, 'P1')) -- place item's instances-of in a set
		local isCat      = instanceOf['Q24']               -- this entity is a instance of Wikimedia category
		-- build a list of sites we will not link to,  so we do not overwrite existing interwiki links
		-- we will overwrite category sitelinks with article sitelinks if both are present
		if qid and (not isCat) then -- in case "entity" already has some sitelinks than exclude them
			excludedProjects = list2set(entity.sitelinks, excludedProjects)
		end
	end
	
	-- build interwiki table based on wikidata page with item ID 'qid'
	local intWikiTable = {}
	if qid then
		entity = mw.wikibase.getEntity(qid)
		if entity and entity.sitelinks then
			for _, sitelink in pairs(entity.sitelinks) do
				local site = sitelink.site -- site names usually have language+"wiki" like "enwiki", etc
				local lang = mw.ustring.sub( site, 1, -5) -- split site into language and project parts
				local proj = mw.ustring.sub( site, -4)
				if not excludedProjects[site] and proj=='wiki' then -- excludes sites on the list as well as Wikisource, Wikiquote, Wikivoyage etc
					lang = mw.ustring.gsub(lang, '_','-') -- if extracted language has any underscores replace it with a minus
					table.insert(intWikiTable, mw.ustring.format(fStr, lang, sitelink.title) ) -- put together a interwiki-link to other projects
				end
			end
		end
	end
	return table.concat(intWikiTable, '\n') -- change table of strings to a single string: one row per line
end

return p