پودمان:Commons link

نسخهٔ تاریخ ‏۲۵ ژوئیهٔ ۲۰۲۱، ساعت ۲۳:۵۶ توسط fa.wikipedia.org>Jeeputer (برای افزودن دو تابع، به‌دلیل گره‌خوردن آن دو تابع با توابع دیگر، به‌ناچار کل پودمان را از ویکی انگلیسی به‌روز کردم. تا جایی که امتحان کردم مشکلی نبود. اگر مشکلی مشاهده کردید این ویرایش را واگردانی کنید و در صفحهٔ بحثم خبرم کنید.)
(تفاوت) → نسخهٔ قدیمی‌تر | نمایش نسخهٔ فعلی (تفاوت) | نسخهٔ جدیدتر ← (تفاوت)

توضیحات این پودمان می‌تواند در پودمان:Commons link/توضیحات قرار گیرد.

-- Module to find commons galleries and categories based on wikidata entries
local getArgs = require('Module:Arguments').getArgs
local yesNo = require('Module:Yesno')
local generateWarning = require('Module:If preview')._warning
local p = {}

-- Check if string is a valid QID
-- Argument: QID to check
-- Returns: valid (bool)
local function _validQID(qid)
	return qid and mw.ustring.find(qid,"^[Qq]%d+$")
end

-- Check if string is a valid wikidata property string
-- Argument: property string to check
-- Returns: valid (bool)
local function _validProp(prop)
	return prop and mw.ustring.find(prop,"^[Pp]%d+$")
end

local function _lcfirst(doit,s)
	if doit then
		return mw.ustring.lower(mw.ustring.sub(s,1,1))..mw.ustring.sub(s,2)
	end
	return s
end

-- Format displayed linktext
-- Arguments:
--   s = string to display
--   formatting = formatting table:
--    formatting.linktext = if defined, override s
--    formatting.lcfirst = lower case the first letter in display
--    formatting.bold = whether to bold the display
--    formatting.italic = whether to italicize the display
--    formatting.nowrap = set nowrapping
-- Returns:
--   formatted string
local function _formatResult(s, formatting)
	local resultVal = formatting.linktext or s
	resultVal = _lcfirst(formatting.lcfirst,resultVal)
	if formatting.italic then resultVal = "<i>" .. resultVal .. "</i>" end
	if formatting.bold then resultVal = "<b>" .. resultVal .. "</b>" end
	if formatting.nowrap then 
		resultVal = '<span style="white-space:nowrap;">' .. resultVal .. "</span>"
	end
	return resultVal
end

-- Get title, namespace, and QID for current page
-- Arguments:
--   qid = testing only: get title of alternative page with QID=qid
--   nsQid = whether to return the ns of the qid page or current
-- Returns:
--   title, namespace (string), qid of current page (or test page)
local function _getTitleQID(qid,nsQid)
	local titleObject = mw.title.getCurrentTitle()
	-- look up qid for current page (if not testing)
	local nsText = mw.ustring.gsub(titleObject.nsText,"_"," ")
	if not _validQID(qid) then
		qid = mw.wikibase.getEntityIdForCurrentPage()
		return titleObject.text, nsText, qid
	end
	-- testing-only path: given a qid, determine title
	-- always use namespace from current page (to suppress tracking cat)
	qid = qid:upper()
	local title = mw.wikibase.getSitelink(qid) or ""
	-- strip any namespace from sitelink
	local firstColon = mw.ustring.find(title,':',1,true)
	local qidNsText = ""
	if firstColon then
		qidNsText = mw.ustring.sub(title,1,firstColon-1)
		title = mw.ustring.sub(title,firstColon+1)
	end
	if nsQid then
		return title, qidNsText, qid
	end
	return title, nsText, qid
end

-- Lookup Commons gallery in Wikidata
-- Arguments:
--   qid = QID of current article
--   fetch = whether to lookup Commons sitelink (bool)
--   commonsSitelink = default value for Commons sitelink
-- Returns:
--   categoryLink = name of Commons category, nil if nothing is found
--   consistent = multiple wikidata fields are examined: are they consistent?
--   commonsSitelink = commons sitelink for current article
local function _lookupGallery(qid,fetch,commonsSitelink)
	if not _validQID(qid) then
		return nil, true, nil
	end
	qid = qid:upper()
	local galleryLink = nil
	local consistent = true
	-- look up commons sitelink for article, use if not category
	if fetch then
		commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki") or commonsSitelink
	end
	if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) ~= "Category:" then
		galleryLink = commonsSitelink
	end
	-- P935 is the "commons gallery" property for this article
	local P935 = mw.wikibase.getBestStatements(qid, "P935")[1]
	if P935 and P935.mainsnak.datavalue then
		local gallery = P935.mainsnak.datavalue.value
		if galleryLink and galleryLink ~= gallery then
			consistent = false
		else
			galleryLink = gallery
		end
	end
	return galleryLink, consistent, commonsSitelink
end

-- Find fallback category by looking up Commons sitelink of different page
-- Arguments:
--    qid = QID for current article
--    property = property that refers to other article whose sitelink to return
-- Returns: either category-stripped name of article, or nil
local function _lookupFallback(qid,property)
	if not _validQID(qid) or not _validProp(property) then
		return nil
	end
	qid = qid:upper()
	property = property:upper()
	-- If property exists on current article, get value (other article qid)
	local value = mw.wikibase.getBestStatements(qid, property)[1]
	if value and value.mainsnak.datavalue and value.mainsnak.datavalue.value.id then
		-- Look up Commons sitelink of other article
		local sitelink = mw.wikibase.getSitelink(value.mainsnak.datavalue.value.id,"commonswiki")
		-- Check to see if it starts with "Category:". If so, strip it and return
		if sitelink and mw.ustring.sub(sitelink,1,9) == "Category:" then
			return mw.ustring.sub(sitelink,10)
		end
	end
	return nil
end

-- Find Commons category by looking in wikidata
-- Arguments:
--   qid = QID of current article
--   fetch = whether to lookup Commons sitelink (bool)
--   commonsSitelink = default value for Commons sitelink
-- Returns:
--   categoryLink = name of Commons category, nil if nothing is found
--   consistent = multiple wikidata fields are examined: are they consistent?
--   commonsSitelink = commons sitelink for current article
local function _lookupCategory(qid, fetch, commonsSitelink)
	if not _validQID(qid) then
		return nil, true, nil
	end
	qid = qid:upper()
	local categoryLink = nil
	local consistent = true
	-- look up commons sitelink for article, use if starts with "Category:"
	if fetch then
		commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki") or commonsSitelink
	end
	if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) == "Category:" then
		categoryLink = mw.ustring.sub(commonsSitelink,10)
	end
	-- purposefully do not look in P373 ("commons category" property)
	-- if P373 is desired, then restore search code here

	-- P910 is the "topic's main category". Look for commons sitelink there
	local fallback = _lookupFallback(qid,"P910")
	if fallback then
		if categoryLink and categoryLink ~= fallback then
			consistent = false
			qid = nil
		else
			categoryLink = fallback
		end
	end
	-- P1754 is the "list's main category". Look for commons sitelink there
	fallback = _lookupFallback(qid,"P1754")
	if fallback then
		if categoryLink and categoryLink ~= fallback then
			consistent = false
		else
			categoryLink = fallback
		end
	end
	return categoryLink, consistent, commonsSitelink
end

-- Does the article have a Commons gallery, and is it consistent?
-- Arguments:
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   filename at Commons, bool: is wikidata consistent for this article?
function p._hasGalleryConsistent(qid)
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	return _lookupGallery(qid,true)
end

-- Does the article have a corresponding Commons gallery?
-- Arguments:
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   filename at Commons if so, false if not
function p._hasGallery(qid)
	local galleryLink, consistent = p._hasGalleryConsistent(qid)
	return consistent and galleryLink
end

-- Does the article have a Commons category? Is wikidata consistent for that?
-- Arguments:
--   qid = QID to lookup in wikidata (for testing only)
--   prefix = whether to add "Category:" to return string (default true)
-- Returns:
--   filename at Commons, bool: consistent
function p._hasCategoryConsistent(qid,prefix)
	if prefix == nil then
		prefix = true
	end
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	local categoryLink, consistent = _lookupCategory(qid,true)
	if categoryLink and prefix then
		categoryLink = "Category:"..categoryLink
	end
	return categoryLink, consistent
end

-- Does the article have a corresponding Commons category?
-- Arguments:
--   qid = QID to lookup in wikidata (for testing only)
--   prefix = whether to add "Category:" to return string (default true)
-- Returns:
--   filename at Commons if so, blank if not
function p._hasCategory(qid,prefix)
	local categoryLink, consistent = p._hasCategoryConsistent(qid,prefix)
	return consistent and categoryLink
end

-- Create Commons link corresponding to current article
-- Arguments:
--   namespace = namespace in Commons ("" for galleries)
--   default = use as Commons link, don't access wikidata
--   search = string to search for
--   fallback = string to search for if wikidata fails
--   formatting = formatting parameters
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   formatted wikilink to Commons in specified namespace
function p._getCommons(namespace,default,search,fallback,formatting,qid)
	local nsColon
	if not namespace or namespace == "" then
		nsColon = ""
	else
		nsColon = namespace..":"
	end
	if default then
		return "[[Commons:"..nsColon..default.."|".._formatResult(default,formatting).."]]"
	end
	if search then
		return "[[Commons:Special:Search/"..nsColon..search.."|".._formatResult(search,formatting).."]]"
	end
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	local commonsLink = nil
	local consistent = true
	if nsColon == "" then
		commonsLink, consistent = _lookupGallery(qid,true)
	elseif namespace:lower() == "category" then
		commonsLink, consistent = _lookupCategory(qid,true)
	end
	-- use wikidata if consistent
	if commonsLink and consistent then
		return "[[Commons:"..nsColon..commonsLink.."|".._formatResult(commonsLink,formatting).."]]"
	end
	-- if not consistent, fall back to search and add to tracking cat
	-- construct default result (which searches for title)
	local searchResult = "[[Commons:Special:Search/"..nsColon..(fallback or wp_title)
		.."|".._formatResult(fallback or wp_title,formatting).."]]"
	if not consistent and wp_ns == "" then
		local friendlyNS
		if nsColon == "" then
			friendlyNS = "نگارخانه"
		elseif namespace:lower() == 'category' then namespace = 'رده'
			friendlyNS = namespace
		end
		searchResult = searchResult.."[[رده:ویکی‌داده متناقض برای "..friendlyNS.." انبار]]"
	end
	return searchResult
end

-- Returns "best" Commons link: first look for gallery, then try category
-- Arguments:
--   default = use as Commons link, don't access wikidata
--   search = string to search for
--   fallback = string to search for if wikidata lookup fails
--   formatting = formatting parameters
--   qid = QID to lookup in wikidata (for testing only)
-- Returns:
--   formatted wikilink to Commons "best" landing page
function p._getGalleryOrCategory(default, search, fallback, formatting, qid)
	if default then
		return "[[Commons:"..default.."|".._formatResult(default,formatting).."]]"
	end
	if search then
		return "[[Commons:Special:Search/"..search.."|".._formatResult(search,formatting).."]]"
	end
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	local trackingCats = ""
	local galleryLink, consistent, commonsSitelink = _lookupGallery(qid,true)
	-- use wikidata if either sitelink or P935 exist, and they both agree
	if galleryLink and consistent then
		return "[[Commons:"..galleryLink.."|".._formatResult(galleryLink,formatting).."]]"
	end
	if not consistent and wp_ns == "" then
		trackingCats = "[[رده:ویکی‌داده متناقض برای نگارخانه انبار]]"
	end
	-- if gallery is not good, fall back looking for category
	local categoryLink
	categoryLink, consistent = _lookupCategory(qid,false,commonsSitelink)
	if categoryLink and consistent then
		return "[[Commons:Category:"..categoryLink.."|".._formatResult(categoryLink,formatting).."]]"..trackingCats
	end
	if not consistent and wp_ns == "" then
		trackingCats = trackingCats.."[[رده:ویکی‌داده متناقض برای رده انبار]]"
	end
	-- return search result looking for title as last attempt
	return "[[Commons:Special:Search/" .. (fallback or wp_title) ..
		"|" .. _formatResult(fallback or wp_title,formatting) .. "]]" .. trackingCats
end

-- Return link(s) Commons gallery, or category, or both from wikidata
-- Arguments:
--   defaultGallery = default gallery link to use, instead of wikidata
--   defaultCategory = default category link to use, instead of wikidata
--   categoryText = if both gallery and category, text to use in category link ("category" by default)
--   oneSearch = only emit one search result
--   formatting = formatting parameters
--   qid = qid of page to lookup in wikidata (testing only)
function p._getGalleryAndCategory(defaultGallery, defaultCategory, 
	categoryText, oneSearch, formatting, qid
	)
	local wp_title, wp_ns
	wp_title, wp_ns, qid = _getTitleQID(qid)
	categoryText = categoryText or "رده"
	local trackingCats = ""
	local galleryLink, galleryConsistent
	local commonsSitelink = nil
	if defaultGallery then
		galleryLink = defaultGallery
		galleryConsistent = true
	else
		galleryLink, galleryConsistent, commonsSitelink = _lookupGallery(qid,true)
	end
	local galleryGood = galleryLink and galleryConsistent
	if not galleryConsistent and wp_ns == "" then
		trackingCats = "[[رده:ویکی‌داده متناقض برای نگارخانه انبار]]"
	end
	local categoryLink, categoryConsistent
	if defaultCategory then
		categoryLink = defaultCategory
		categoryConsistent = true
	else
		categoryLink, categoryConsistent = _lookupCategory(qid,defaultGallery,commonsSitelink)
	end
	local categoryGood = categoryLink and categoryConsistent
	if not categoryConsistent and wp_ns == "" then
		trackingCats = trackingCats.."[[رده:ویکی‌داده متناقض برای رده انبار]]"
	end
	local firstLink
	-- construct default result (which searches for title)
	local searchResult = "[[Commons:Special:Search/"..wp_title.."|".._formatResult(wp_title,formatting).."]]"
	if not oneSearch then
		searchResult = searchResult.." ([[Commons:Special:Search/Category:"..wp_title.."|"..categoryText.."]])"
	end
	local linkText = nil
	if galleryGood then
		firstLink = galleryLink
		linkText = galleryLink
	elseif categoryGood then
		firstLink = "Category:"..categoryLink
		linkText = categoryLink
	else
		return searchResult..trackingCats
	end
	local resultVal = "[[Commons:"..firstLink.."|".._formatResult(linkText,formatting).."]]"
	if galleryGood and categoryGood then
		resultVal = resultVal.." ([[Commons:Category:"..categoryLink.."|"..categoryText.."]])"
	end
	return resultVal..trackingCats
end

-- Compare two titles with their namespaces stripped
local function titleMatch(s1,s2)
	s1 = s1 or ""
	s2 = s2 or ""
    s1 = mw.ustring.gsub(s1,"^[^:]+:","")
    s2 = mw.ustring.gsub(s2,"^[^:]+:","")
    return s1 == s2
end

local galleryTrackingCats = {
	commons_link_on_wikidata = '[[رده:پیوند انبار در ویکی‌داده است]]',
	commons_link_defined_as_pagename = '[[رده:پیوند انبار مانند نام صفحه تعریف شده‌است]]',
	commons_link_locally_defined = '[[رده:پیوند انبار به‌صورت محلی تعریف شده‌است]]',
	commons_link_from_wikidata = '[[رده:پیوند انبار از ویکی‌داده]]',
	commons_link_is_pagename = '[[رده:پیوند انبار نام صفحه است]]',
	inconsistent = '[[رده:ویکی‌داده متناقض برای نگارخانه انبار]]'
}

local categoryTrackingCats = {
		commons_link_on_wikidata = '[[رده:پیوند رده انبار در ویکی‌داده است]]',
		commons_link_defined_as_pagename = '[[رده:پیوند رده انبار مانند نام صفحه تعریف شده‌است]]',
		commons_link_locally_defined = '[[رده:پیوند رده انبار که به صورت محلی تعریف شده است]]',
		commons_link_from_wikidata = '[[رده:پیوند رده انبار از ویکی‌داده]]',
		commons_link_is_pagename = '[[رده:پیوند رده انبار همان نام صفحه است]]',
		inconsistent = '[[رده:ویکی‌داده متناقض برای رده انبار]]'
	}

local function selectTrackingCat(trackingCats,wikidata,consistent,default,title)
	if not consistent then
		return trackingCats.inconsistent
	end
	if default then
	-- construct warning message
		if default == wikidata then
			return trackingCats.commons_link_on_wikidata
		end
		local warning = ""
		if wikidata then
			warning = generateWarning({
					"پیوند ویکی‌انبار با ویکی‌داده منطبق نیست – [[:en:Template:Commons_category#Resolving_discrepancies|لطفاً بررسی کنید]]"
				})
		end
		if titleMatch(default,title) then
			return trackingCats.commons_link_defined_as_pagename .. warning
		end
		return trackingCats.commons_link_locally_defined .. warning
	end
	if wikidata then
		return trackingCats.commons_link_from_wikidata
	end
	return trackingCats.commons_link_is_pagename
end

-- Figure out tracking categories and editor warnings
-- Arguments:
--   default = Commons link argument passed to template
--   fetchGallery = whether to fetch a gallery from Wikidata
--   fetchCategory = whether to fetch a category from Wikidata
--   qid = force a qid for testing
-- Returns:
--   tracking category and possible user warning
--
-- Note: the logic for the tracking is quite different than the logic
-- for generating Commons links (above). Thus, it is separated into another
-- function for code clarity and maintainability. This should not seriously 
-- affect performance: server time is dominated by fetching wikidata entities,
-- and those entities should be cached and shared between the Commons generating
-- code and this tracking code.
function p._tracking(default, fetchGallery, fetchCategory, qid)
	local title, wp_ns, wp_qid = _getTitleQID(qid,true)
	if wp_ns ~= "" then
		title = wp_ns..":"..title
	end
	-- only track if test or namespace=article or namespace=category
	if not (qid or wp_ns == "" or wp_ns == "رده") then
		return ""
	end
	
	-- determine title and namespace of wikidata and wp article
	local wikidata = nil
	local consistent = nil
	-- Tracking code works for all 4 cases of states of fetchGallery/Category
	-- fetchGallery takes precedence
	if fetchGallery then
		wikidata, consistent = p._hasGalleryConsistent(qid)
		if default or not fetchCategory or (consistent and wikidata) then
			return selectTrackingCat(galleryTrackingCats,wikidata,consistent,
				                     default,title)
		end
	end
    if fetchCategory then
		cat_wikidata, cat_consistent = p._hasCategoryConsistent(qid,true)
		if not fetchGallery or (cat_consistent and cat_wikidata) then
			return selectTrackingCat(categoryTrackingCats,cat_wikidata,
			                    	 cat_consistent,default,title)
		end
		return selectTrackingCat(galleryTrackingCats,wikidata,consistent,
			                     default,title)
    end
	return "" -- nothing fetched, nothing tracked
end

local function _createFormatting(args)
	formatting = {}
	formatting.linktext = args.linktext
	formatting.lcfirst = yesNo(args.lcfirst)
	formatting.bold = yesNo(args.bold)
	formatting.italic = yesNo(args.italic)
	formatting.nowrap = yesNo(args.nowrap)
	return formatting
end

-- Testing-only entry point for _getTitleQID
function p.getTitleQID(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local text, ns, qid = _getTitleQID(args[1],args[2])
	return text..","..ns..","..(qid or "nil")
end

-- Testing-only entry point for _lookupFallback
function p.lookupFallback(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local fallback = _lookupFallback(args[1],args[2])
	return fallback or "nil"
end

-- Find the Commons gallery page associated with article
function p.getGallery(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._getCommons("",args[1],args.search,args.fallback,_createFormatting(args),args.qid)
end

-- Find the Commons category page associated with article
function p.getCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local retval = p._getCommons("Category", args[1], 
		args.search, args.fallback, _createFormatting(args), args.qid
	)
	if args.tracking then
		local default = nil
		if args[1] then
			default = "Category:"..args[1]
		end
		retval = retval..p._tracking(default, false, true, args.qid)
	end
	return retval
end

function p.getGalleryOrCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	local retval = p._getGalleryOrCategory(
		args[1], args.search, args.fallback, _createFormatting(args), args.qid
	)
	if args.tracking then
		retval = retval..p._tracking(args[1],true,true,args.qid)
	end
	return retval
end

function p.hasGallery(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._hasGallery(args.qid) or ""
end

function p.hasCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._hasCategory(args.qid) or ""
end

function p.hasGalleryOrCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._hasGallery(args.qid) or p._hasCategory(args.qid) or ""
end

function p.getGalleryAndCategory(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._getGalleryAndCategory(args[1], args[2], 
		args.categoryText, args.oneSearch, _createFormatting(args), args.qid)
end

function p.tracking(frame)
	local args = getArgs(frame,{frameOnly=true,parentOnly=false,parentFirst=false})
	return p._tracking(args[1], args.fetchGallery, args.fetchCategory, args.qid)
end

return p