Module:Commons link: Difference between revisions
From All Skies Encyclopaedia
imported>Hike395  (add search parameter)  | 
				imported>Hike395   (lazy load module)  | 
				||
| (39 intermediate revisions by 6 users not shown) | |||
| Line 1: | Line 1: | ||
require('strict')  | 
|||
-- Module to find commons galleries and categories based on wikidata entries  | 
  -- Module to find commons galleries and categories based on wikidata entries  | 
||
local getArgs = require('Module:Arguments').getArgs  | 
  local getArgs = require('Module:Arguments').getArgs  | 
||
local p = {}  | 
  local p = {}  | 
||
-- Check if string is a valid QID  | 
|||
-- Find the Commons gallery page associated with article  | 
  |||
-- Argument: QID to check  | 
|||
function p.getGallery(frame)  | 
  |||
-- Returns: valid (bool)  | 
|||
	local args = getArgs(frame)  | 
  |||
local function _validQID(qid)  | 
|||
	return p._getGallery(args[1],args.linktext,args.search,args.qid)  | 
  |||
	return qid and mw.ustring.find(qid,"^[Qq]%d+$")  | 
|||
end  | 
  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(s)  | 
|||
	return mw.ustring.lower(mw.ustring.sub(s,1,1))..mw.ustring.sub(s,2)  | 
|||
end  | 
|||
-- Format displayed linktext  | 
|||
-- Arguments:  | 
  -- Arguments:  | 
||
--   s = string to display  | 
|||
--   default = use as Commons link, don't access wikidata  | 
  |||
--   formatting = formatting table:  | 
|||
--   linktext = text to display in link  | 
  |||
--    formatting.linktext = if defined, override s  | 
|||
--   search = string to search for  | 
  |||
--    formatting.lcfirst = lower case the first letter in display  | 
|||
--   qid = QID to lookup in wikidata (for testing only)  | 
  |||
--    formatting.bold = whether to bold the display  | 
|||
function p._getGallery(default,linktext,search,qid)  | 
  |||
--    formatting.italic = whether to italicize the display  | 
|||
	if default then  | 
  |||
--    formatting.nowrap = set nowrapping  | 
|||
		return "[[Commons:"..default.."|"..(linktext or default).."]]"  | 
  |||
-- Returns:  | 
|||
--   formatted string  | 
|||
local function _formatResult(s, formatting)  | 
|||
	local resultVal = formatting.linktext or s  | 
|||
	if formatting.lcfirst then  | 
|||
		resultVal = _lcfirst(resultVal)  | 
|||
	end  | 
  	end  | 
||
    local style = ""  | 
|||
	if formatting.italic then style = "font-style:italic; " end  | 
|||
	if formatting.bold then style = style.."font-weight:bold; " end  | 
|||
	if formatting.nowrap then style = style.."white-space:nowrap; " end  | 
|||
    if style ~= "" then  | 
|||
    	resultVal = '<span style="'..mw.text.trim(style)..'">'..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()  | 
  	local titleObject = mw.title.getCurrentTitle()  | 
||
	-- look up qid for current page (if not testing)  | 
|||
	local title = titleObject.text  | 
  |||
	local nsText = string.gsub(titleObject.nsText,"_"," ") -- [[phab:T369784]]  | 
|||
	qid = (qid or ""):upper()  | 
  |||
	if qid  | 
  	if not _validQID(qid) then  | 
||
		-- look up qid for current page (if not testing)  | 
  |||
		qid = mw.wikibase.getEntityIdForCurrentPage()  | 
  		qid = mw.wikibase.getEntityIdForCurrentPage()  | 
||
		return titleObject.text, nsText, qid  | 
|||
	else  | 
  |||
		-- if qid specified, look up title from that  | 
  |||
	    title = mw.wikibase.sitelink(qid)  | 
  |||
	end  | 
  	end  | 
||
	--   | 
  	-- testing-only path: given a qid, determine title  | 
||
	-- always use namespace from current page (to suppress tracking cat)  | 
|||
	local searchResult = "[[Commons:Special:Search/"..(search or title).."|"..(linktext or title).."]]"  | 
  |||
	qid = qid:upper()  | 
|||
	local title = mw.wikibase.getSitelink(qid) or ""  | 
|||
		local galleryLink = nil  | 
  |||
	-- strip any namespace from sitelink  | 
|||
		local consistent = true  | 
  |||
	local firstColon = mw.ustring.find(title,':',1,true)  | 
|||
		-- look up commons sitelink for article, use if not category  | 
  |||
	local qidNsText = ""  | 
|||
		local commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki")  | 
  |||
	if firstColon then  | 
|||
		if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) ~= "Category:" then  | 
  |||
		qidNsText = mw.ustring.sub(title,1,firstColon-1)  | 
|||
			galleryLink = commonsSitelink  | 
  |||
		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  | 
||
	end  | 
|||
		-- P935 is the "commons gallery" property for this article  | 
  |||
	return galleryLink, consistent, commonsSitelink  | 
|||
		local P935 = mw.wikibase.getBestStatements(qid, "P935")[1]  | 
  |||
end  | 
|||
		if P935 and P935.mainsnak.datavalue then  | 
  |||
			local gallery = P935.mainsnak.datavalue.value  | 
  |||
-- Find fallback category by looking up Commons sitelink of different page  | 
|||
			if galleryLink and galleryLink ~= gallery then  | 
  |||
-- Arguments:  | 
|||
				consistent = false  | 
  |||
--    qid = QID for current article  | 
|||
			else  | 
  |||
--    property = property that refers to other article whose sitelink to return  | 
|||
				galleryLink = gallery  | 
  |||
-- Returns: either category-stripped name of article, or nil  | 
|||
			end  | 
  |||
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  | 
||
	end  | 
|||
		-- use wikidata if either sitelink or P935 exist, and they both agree  | 
  |||
	return nil  | 
|||
		if galleryLink and consistent then  | 
  |||
end  | 
|||
			return "[[Commons:"..galleryLink.."|"..(linktext or galleryLink).."]]"  | 
  |||
-- 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  | 
|||
	-- 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  | 
||
	end  | 
|||
		-- if not consistent, fall back to search and add to tracking cat  | 
  |||
	-- P1754 is the "list's main category". Look for commons sitelink there  | 
|||
		if not consistent and titleObject.namespace == 0 then  | 
  |||
	fallback = _lookupFallback(qid,"P1754")  | 
|||
			searchResult = searchResult.."[[Category:Inconsistent wikidata for Commons gallery]]"  | 
  |||
	if fallback then  | 
|||
		if categoryLink and categoryLink ~= fallback then  | 
|||
			consistent = false  | 
|||
			qid = nil  | 
|||
		else  | 
|||
			categoryLink = fallback  | 
|||
		end  | 
  		end  | 
||
	end  | 
  	end  | 
||
    -- P373 is the "commons category" property for this article. This is  | 
|||
	return searchResult  | 
  |||
    -- a low-quality field, so should only be used as a last resort.  | 
|||
    if categoryLink == nil and _validQID(qid) then  | 
|||
	    local P373 = mw.wikibase.getBestStatements(qid, "P373")[1]  | 
|||
	    if P373 and P373.mainsnak.datavalue then  | 
|||
		    categoryLink = P373.mainsnak.datavalue.value  | 
|||
		    consistent = true  -- P373 is never used if anything else is available  | 
|||
		end  | 
|||
	end  | 
|||
	return categoryLink, consistent, commonsSitelink  | 
|||
end  | 
  end  | 
||
--   | 
  -- Does the article have a Commons gallery, and is it consistent?  | 
||
-- Arguments:  | 
|||
function p.getCategory(frame)  | 
  |||
--   qid = QID to lookup in wikidata (for testing only)  | 
|||
	local args = getArgs(frame)  | 
  |||
-- Returns:  | 
|||
	return p._getCategory(args[1],args.linktext,args.search,args.qid)  | 
  |||
--   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  | 
  end  | 
||
-- Does the article have a corresponding Commons gallery?  | 
|||
-- Arguments:  | 
  -- Arguments:  | 
||
--     | 
  --   qid = QID to lookup in wikidata (for testing only)  | 
||
-- Returns:  | 
|||
--   linktext = text to display in link  | 
  |||
--   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  | 
  --   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)  | 
  --   qid = QID to lookup in wikidata (for testing only)  | 
||
-- Returns:  | 
|||
function p._getCategory(default,linktext,search,qid)  | 
  |||
--   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  | 
  	if default then  | 
||
		return "[[Commons  | 
  		return "[[Commons:"..nsColon..default.."|".._formatResult(default,formatting).."]]"  | 
||
	end  | 
  	end  | 
||
	if search then  | 
|||
	local titleObject = mw.title.getCurrentTitle()  | 
  |||
		return "[[Commons:Special:Search/"..nsColon..search.."|".._formatResult(search,formatting).."]]"  | 
|||
	local title = titleObject.text  | 
  |||
	end  | 
|||
	qid = (qid or ""):upper()  | 
  |||
	local wp_title, wp_ns  | 
|||
	if qid == "" then  | 
  |||
	wp_title, wp_ns, qid = _getTitleQID(qid)  | 
|||
		-- look up qid for current page (if not testing)  | 
  |||
	local commonsLink = nil  | 
|||
		qid = mw.wikibase.getEntityIdForCurrentPage()  | 
  |||
	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 = "gallery"  | 
|||
		else  | 
|||
			friendlyNS = namespace:lower()  | 
|||
		end  | 
|||
		searchResult = searchResult.."[[Category:Inconsistent wikidata for Commons "..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 = "[[Category:Inconsistent wikidata for Commons gallery]]"  | 
|||
	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.."[[Category:Inconsistent wikidata for Commons category]]"  | 
|||
	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 "category"  | 
|||
	local trackingCats = ""  | 
|||
	local galleryLink, galleryConsistent  | 
|||
	local commonsSitelink = nil  | 
|||
	if defaultGallery then  | 
|||
		galleryLink = defaultGallery  | 
|||
		galleryConsistent = true  | 
|||
	else  | 
  	else  | 
||
		galleryLink, galleryConsistent, commonsSitelink = _lookupGallery(qid,true)  | 
|||
		-- if qid specified, look up title from that  | 
  |||
	    title = mw.wikibase.sitelink(qid)  | 
  |||
	end  | 
  	end  | 
||
	local galleryGood = galleryLink and galleryConsistent  | 
|||
	-- construct default result (which searches for title in Category space)  | 
  |||
	if not galleryConsistent and wp_ns == "" then  | 
|||
	local searchResult = "[[Commons:Special:Search/Category:"..(search or title).."|"..(linktext or title).."]]"  | 
  |||
		trackingCats = "[[Category:Inconsistent wikidata for Commons gallery]]"  | 
|||
	if qid then  | 
  |||
	end  | 
|||
		local categoryLink = nil  | 
  |||
	local categoryLink, categoryConsistent  | 
|||
		local consistent = true  | 
  |||
	if defaultCategory then  | 
|||
		-- look up commons sitelink for article, use if starts with "Category:"  | 
  |||
		categoryLink = defaultCategory  | 
|||
		local commonsSitelink = mw.wikibase.getSitelink(qid,"commonswiki")  | 
  |||
		categoryConsistent = true  | 
|||
		if commonsSitelink and mw.ustring.sub(commonsSitelink,1,9) == "Category:" then  | 
  |||
	else  | 
|||
			categoryLink = mw.ustring.sub(commonsSitelink,10)  | 
  |||
		categoryLink, categoryConsistent = _lookupCategory(qid,defaultGallery,commonsSitelink)  | 
|||
	end  | 
|||
	local categoryGood = categoryLink and categoryConsistent  | 
|||
	if not categoryConsistent and wp_ns == "" then  | 
|||
		trackingCats = trackingCats.."[[Category:Inconsistent wikidata for Commons category]]"  | 
|||
	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 = '[[Category:Commons link is on Wikidata]]',  | 
|||
	commons_link_defined_as_pagename = '[[Category:Commons link is defined as the pagename]]',  | 
|||
	commons_link_locally_defined = '[[Category:Commons link is locally defined]]',  | 
|||
	commons_link_from_wikidata = '[[Category:Commons link from Wikidata]]',  | 
|||
	commons_link_is_pagename = '[[Category:Commons link is the pagename]]',  | 
|||
	inconsistent = '[[Category:Inconsistent wikidata for Commons gallery]]'  | 
|||
}  | 
|||
local categoryTrackingCats = {  | 
|||
		commons_link_on_wikidata = '[[Category:Commons category link is on Wikidata]]',  | 
|||
		commons_link_defined_as_pagename = '[[Category:Commons category link is defined as the pagename]]',  | 
|||
		commons_link_locally_defined = '[[Category:Commons category link is locally defined]]',  | 
|||
		commons_link_from_wikidata = '[[Category:Commons category link from Wikidata]]',  | 
|||
		commons_link_is_pagename = '[[Category:Commons category link is the pagename]]',  | 
|||
		inconsistent = '[[Category:Inconsistent wikidata for Commons category]]'  | 
|||
	}  | 
|||
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  | 
  		end  | 
||
		local warning = ""  | 
|||
		-- P935 is the "commons category" property for this article  | 
  |||
		if wikidata then  | 
|||
		local P373 = mw.wikibase.getBestStatements(qid, "P373")[1]  | 
  |||
			local generateWarning = require('Module:If preview')._warning  | 
|||
		if P373 and P373.mainsnak.datavalue then  | 
  |||
			warning = generateWarning({  | 
|||
			P373 = P373.mainsnak.datavalue.value  | 
  |||
					"Commons link does not match Wikidata – [[Template:Commons_category#Resolving_discrepancies|please check]]"  | 
|||
			if categoryLink and categoryLink ~= P373 then  | 
  |||
				})  | 
|||
				consistent = false  | 
  |||
			else  | 
  |||
				categoryLink = P373  | 
  |||
			end  | 
  |||
		end  | 
  		end  | 
||
		if titleMatch(default,title) then  | 
|||
		-- P910 is the "topic's main category". Look for commons sitelink there  | 
  |||
			return trackingCats.commons_link_defined_as_pagename .. warning  | 
|||
		local P910 = mw.wikibase.getBestStatements(qid, "P910")[1]  | 
  |||
		if P910 and P910.mainsnak.datavalue and P910.mainsnak.datavalue.value.id then  | 
  |||
			P910 = P910.mainsnak.datavalue.value.id  | 
  |||
			local fallback = mw.wikibase.getSitelink(P910, "commonswiki")  | 
  |||
			if fallback and mw.ustring.sub(fallback,1,9) == "Category:" then  | 
  |||
				fallback = mw.ustring.sub(fallback,10)  | 
  |||
				if categoryLink and categoryLink ~= fallback then  | 
  |||
					consistent = false  | 
  |||
				else  | 
  |||
					categoryLink = fallback  | 
  |||
				end  | 
  |||
			end  | 
  |||
		end  | 
  		end  | 
||
		return trackingCats.commons_link_locally_defined .. warning  | 
|||
		-- if any of sitelink category, P373, and P910 commons sitelink exist,  | 
  |||
	end  | 
|||
		-- use it. But don't use if they don't agree with each other  | 
  |||
	if wikidata then  | 
|||
		return trackingCats.commons_link_from_wikidata  | 
|||
			return "[[Commons:Category:"..categoryLink.."|"..(linktext or categoryLink).."]]"  | 
  |||
	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 == "Category") 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  | 
||
	end  | 
|||
		-- if not consistent, fall back to search, but add tracking category  | 
  |||
    if fetchCategory then  | 
|||
		if not consistent and titleObject.namespace == 0 then  | 
  |||
		local cat_wikidata, cat_consistent = p._hasCategoryConsistent(qid,true)  | 
|||
			searchResult = searchResult.."[[Category:Inconsistent wikidata for Commons category]]"  | 
  |||
		if not fetchGallery or (cat_consistent and cat_wikidata) then  | 
|||
			return selectTrackingCat(categoryTrackingCats,cat_wikidata,  | 
|||
			                    	 cat_consistent,default,title)  | 
|||
		end  | 
  		end  | 
||
		return selectTrackingCat(galleryTrackingCats,wikidata,consistent,  | 
|||
			                     default,title)  | 
|||
    end  | 
|||
	return "" -- nothing fetched, nothing tracked  | 
|||
end  | 
|||
local function _createFormatting(args)  | 
|||
	local formatting = {}  | 
|||
	formatting.linktext = args.linktext  | 
|||
    local yesNo = require('Module:Yesno')  | 
|||
	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  | 
  	end  | 
||
	return   | 
  	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  | 
  end  | 
||
Latest revision as of 10:43, 24 October 2024
Documentation for this module may be created at Module:Commons link/doc
require('strict')
-- Module to find commons galleries and categories based on wikidata entries
local getArgs = require('Module:Arguments').getArgs
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(s)
	return mw.ustring.lower(mw.ustring.sub(s,1,1))..mw.ustring.sub(s,2)
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
	if formatting.lcfirst then
		resultVal = _lcfirst(resultVal)
	end
    local style = ""
	if formatting.italic then style = "font-style:italic; " end
	if formatting.bold then style = style.."font-weight:bold; " end
	if formatting.nowrap then style = style.."white-space:nowrap; " end
    if style ~= "" then
    	resultVal = '<span style="'..mw.text.trim(style)..'">'..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 = string.gsub(titleObject.nsText,"_"," ") -- [[phab:T369784]]
	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
	-- 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
			qid = nil
		else
			categoryLink = fallback
		end
	end
    -- P373 is the "commons category" property for this article. This is
    -- a low-quality field, so should only be used as a last resort.
    if categoryLink == nil and _validQID(qid) then
	    local P373 = mw.wikibase.getBestStatements(qid, "P373")[1]
	    if P373 and P373.mainsnak.datavalue then
		    categoryLink = P373.mainsnak.datavalue.value
		    consistent = true  -- P373 is never used if anything else is available
		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 = "gallery"
		else
			friendlyNS = namespace:lower()
		end
		searchResult = searchResult.."[[Category:Inconsistent wikidata for Commons "..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 = "[[Category:Inconsistent wikidata for Commons gallery]]"
	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.."[[Category:Inconsistent wikidata for Commons category]]"
	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 "category"
	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 = "[[Category:Inconsistent wikidata for Commons gallery]]"
	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.."[[Category:Inconsistent wikidata for Commons category]]"
	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 = '[[Category:Commons link is on Wikidata]]',
	commons_link_defined_as_pagename = '[[Category:Commons link is defined as the pagename]]',
	commons_link_locally_defined = '[[Category:Commons link is locally defined]]',
	commons_link_from_wikidata = '[[Category:Commons link from Wikidata]]',
	commons_link_is_pagename = '[[Category:Commons link is the pagename]]',
	inconsistent = '[[Category:Inconsistent wikidata for Commons gallery]]'
}
local categoryTrackingCats = {
		commons_link_on_wikidata = '[[Category:Commons category link is on Wikidata]]',
		commons_link_defined_as_pagename = '[[Category:Commons category link is defined as the pagename]]',
		commons_link_locally_defined = '[[Category:Commons category link is locally defined]]',
		commons_link_from_wikidata = '[[Category:Commons category link from Wikidata]]',
		commons_link_is_pagename = '[[Category:Commons category link is the pagename]]',
		inconsistent = '[[Category:Inconsistent wikidata for Commons category]]'
	}
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
			local generateWarning = require('Module:If preview')._warning
			warning = generateWarning({
					"Commons link does not match Wikidata – [[Template:Commons_category#Resolving_discrepancies|please check]]"
				})
		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 == "Category") 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
		local 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)
	local formatting = {}
	formatting.linktext = args.linktext
    local yesNo = require('Module:Yesno')
	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




