Module:Wikidata label

    From Commons

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

    --[[  
      __  __           _       _      __        ___ _    _     _       _          _       _          _ 
     |  \/  | ___   __| |_   _| | ___ \ \      / (_) | _(_) __| | __ _| |_ __ _  | | __ _| |__   ___| |
     | |\/| |/ _ \ / _` | | | | |/ _ (_) \ /\ / /| | |/ / |/ _` |/ _` | __/ _` | | |/ _` | '_ \ / _ \ |
     | |  | | (_) | (_| | |_| | |  __/_ \ V  V / | |   <| | (_| | (_| | || (_| | | | (_| | |_) |  __/ |
     |_|  |_|\___/ \__,_|\__,_|_|\___(_) \_/\_/  |_|_|\_\_|\__,_|\__,_|\__\__,_| |_|\__,_|_.__/ \___|_|
                                                                                                       
    This module is intended to be the engine behind "Template:Label".
    Thic module was copied from Commons please ask for changes there.
    
    Please do not modify this code without applying the changes first at "Module:Wikidata label/sandbox" and testing 
    at "Module:Wikidata label/testcases".
    
    Authors and maintainers:
    * User:Jarekt - original version 
    
    Dependencies:
    * Module:Yesno - used only if "show_id" parameter present
    ]]
    
    -- ==================================================
    -- === Internal functions ===========================
    -- ==================================================
    
    -- use different sitelink call depending if you already have an entity or not
    local function getSitelink(item, entity, lang)
    	if entity and entity.getSitelink then -- if we have entity than use it
    		return entity:getSitelink(lang .. 'wiki') 
    	else -- if no entity than use different function
    		return mw.wikibase.sitelink( item, lang .. 'wiki' )
    	end
    end
    
    ----------------------------------------------------------------------------------
    -- change capitalization of the label
    local function	apply_capitalization(label, capitalization, lang)
    	if capitalization=='ucfirst' then
    		label = mw.language.new(lang):ucfirst(label)
    	elseif capitalization=='lcfirst' then
    		label = mw.language.new(lang):lcfirst(label)
    	elseif capitalization=='uc' then
    		label = mw.language.new(lang):uc(label)
    	elseif capitalization=='lc' then
    		label = mw.language.new(lang):lc(label)
    	end
    	return label
    end
    
    ------------------------------------------------------------------------------
    -- Function allowing for consistent treatment of boolean-like wikitext input.
    -- It works similarly to Module:Yesno
    local function yesno(val, default)
    	if type(val) == 'boolean' then
    		return val
    	elseif type(val) == 'number' then
    		if val==1 then 
    			return true
    		elseif val==0 then
    			return false
    		end
    	elseif type(val) == 'string' then
    	    val = mw.ustring.lower(val)  -- put in lower case
    	    if val == 'no'  or val == 'n' or val == 'false' or val == '0' then
    	        return false
    	    elseif val == 'yes' or val == 'y' or val == 'true' or val == '1' then
    	        return true
    	    end
        end
        return default
    end
    
    -- ==================================================
    -- === External functions ===========================
    -- ==================================================
    local p = {}
    
    -- ===========================================================================
    -- === Version of the function to be called from other LUA codes
    -- ===========================================================================
    
    --[[
    _getLabel
    
    This function returns a label translated to desired language, created based on wikidata
    
    Inputs:
    	1: item - wikidata's item's q-code or entity class
    	2: lang - desired language of the label
    	3: link_type - link style. Possible values: "wikipedia", "Wikidata", "Commons", or "-" (no link)
    	4: capitalization - can be "uc" (upper case), "lc" (lower case), "ucfirst" (upper case for the first letter), 
    			"lcfirst" (lower case for the first letter)
     
    Error Handling:
    	Bad q-code will result in displayed error
    ]]
    function p._getLabel(item, lang, link_type, capitalization, show_id)
    	local entity, s, link, label, language
    
    	-- clean up the input parameters
    	if type(item)~='string' then -- "item" is not a q-code
    		entity = item            -- "item" must be the entity
    		item   = entity.id       -- look-up q-code
    	elseif tonumber(item) then   -- if it is just the number than add "Q" in front
    		item = 'Q'..item
    	end
    	item = string.gsub( string.upper(item), 'PROPERTY:P', 'P') -- make all the properties the same and capitalize
    	
    	-- build language fallback list
    	lang = string.lower(lang) or 'en'
    	local langList = mw.language.getFallbacksFor(lang)
    	table.insert(langList, 1, lang)
    	
    	-- get label (visible part of the link)
    	for _, language in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
    		if entity then
    			label = entity:getLabel(language)
    		else
    			label = mw.wikibase.getLabelByLang(item, language)
    		end
    		if label then break end                    -- label found and we are done
    	end
    	if not label then                              -- no labels found, so just show the q-code
    		label = item
    	elseif show_id then           -- add id
    		show_id = yesno(show_id,false)
    		if show_id then 
    			local id = mw.getCurrentFrame():preprocess( "{{int:parentheses|" .. item .."}}")
    			local wordsep  = mw.message.new( "Word-separator" ):inLanguage(lang):plain()
    			label = label .. wordsep .. "<small>" .. id .. "</small>"
    		end
    	end
    	
    	-- change capitalization of the label
    	label = apply_capitalization(label, capitalization, lang)
    
    	-- create URL part of the link
    	link_type = string.lower(link_type or '')
    	local item_type = string.sub(item, 1, 1) -- item's first letter:Q, P or M
    	local proj = (item_type=='M' and 'c') or 'd' -- link to Commons or to Wikidata
    	local eLink = proj..':Special:EntityPage/'..item -- wikidata (WD) link
    	if link_type=='-' then -- allow different link formats
    		link = ''            -- no link
    	elseif link_type=='wikidata' or item_type=='M' then
    		link = eLink         -- link to wikibase entity page
    	elseif link_type=='wikidata talk' and item_type=='P' then
    		link = 'd:Property talk:'.. item        -- link to wikidata property talk page
    	elseif link_type=='wikidata talk' then
    		link = 'd:Talk:'..item         -- link to wikidata talk page
    	elseif link_type=='commons' or link_type=='commonscat' then
    		-- For link_type=='commons' we try the following links (in that order): 
    		--   1) sitelink to commons 
    		--   2) "Commons Category" P373 property 
    		--   3) "Commons Gallery"  P935 property
    		-- Since most pages have a sitelink to commons we never have to call expensive mw.wikibase.getEntity
    		-- For link_type=='commonscat' we try to maximize chances of commons link beeing a category, so we 
    		--       try the following links (in that order): 
    		--   1) sitelink to commons, which is kept if it points to a category
    		--   2) "Commons Category" P373 property 
    		--   3) sitelink to commons (which does not point to a category)
    		--   4) "Commons Gallery"  P935 property
    		-- Since most pages have a sitelink to commons we never have to call expensive mw.wikibase.getEntity
    		local sLink = getSitelink(item, entity, 'commons')  -- look for sitelink to commons
    		if sLink then 
    			sLink = 'c:'..sLink
    			if (link_type=='commons') or (link_type=='commonscat' and string.find( sLink, 'Category:')) then
    				link = sLink
    			end
    		end
    		if not link then -- try linking to P373 category
    			-- this is potentially memory expensive operation
    			entity = entity or mw.wikibase.getEntity(item); 
    			assert(entity, "Item ID " .. item .. " is not valid")
    			s = entity:getBestStatements( 'P373' )
    			if s[1] and s[1].mainsnak.datavalue.value then 
    				 link = 'c:Category:' .. s[1].mainsnak.datavalue.value
    			end
    		end
    		link = link or sLink
    		if not link then -- try linking to P935 gallery
    			-- there is no need for mw.wikibase.getEntity(item) call since at this point it was already loded
    			s = entity:getBestStatements( 'P935' )
    			if s[1] and s[1].mainsnak.datavalue.value then 
    				 link = s[1].mainsnak.datavalue.value
    			end
    		end
    	end
    	if not link then-- apply default "Wikipedia" link type
    		for _, language in ipairs(langList) do 
    			local sitelink = getSitelink(item, entity, language)
    			if sitelink then 
    				link = mw.ustring.format('w:%s:%s', language, sitelink)
    				break 
    			end
    		end
    	end
    	link = link or eLink  -- no wiki sitelink, so link to wikidata
    	
    	-- return the results
    	if link~='' then
    		return mw.ustring.format('[[%s|%s]]', link, label) -- return link
    	else
    		return label -- return just the label
    	end
    end
    
    --[[
    _sitelinks
    
    This function returns a table of sitelinks for a single project organized by language
    
    Inputs:
    	1: item - wikidata's item's q-code or entity class
    	2: project - "wikipedia", "wikisource", "wikiquote", "wikibooks", "wikinews", "wikiversity", 
    			"wikivoyage", "wiktionary", "commons", "mediawiki", "wikispecies", "wikidata",  etc.
    
    Output:
    	Table with language fields
    ]]
    function p._sitelinks( item, project )
    	local entity, sitelink
    	-- get entity
    	if type(item)=='string' then -- "item" is a q-code
    		entity = mw.wikibase.getEntity(item); 
    	else
    		entity = item            -- "item" is the entity
    		item   = entity.id       -- look-up q-code
    	end
    	
    	-- get project code
    	local LUT = {wikipedia='wiki', commons='commonswiki', mediawiki='mediawikiwiki', wikispecies='specieswiki', wikidata='wikidatawiki'}
    	project = string.lower(project)
    	if LUT[project] then -- correct the project name
    		project=LUT[project]
    	end
    	local n = string.len(project);
    	local s ={}
    	if entity and entity.sitelinks then 					  -- See if entity exists, and that it has sitelinks
    		for _, sitelink in pairs(entity.sitelinks) do 				-- loop over all sitelinks
    		  local site = sitelink.site
    			local lang = mw.ustring.sub( site, 1, mw.ustring.len(site) - n  )  -- language part of the siteID
    			local proj = mw.ustring.sub( site, mw.ustring.len(site) - n + 1 )  -- project part of the siteID
    			if proj == project then -- proj matches desired "project"
    				s[lang] = sitelink.title
    			end
    		end
    	end
    	return s
    end
    
    --[[
    _aliases
    
    This function returns a table of aliases for a single language
    
    Inputs:
    	1: item - wikidata's item's q-code or entity class
    	2: lang - language code, like 'en' or 'de'
    
    Output:
    	Table of aliases
    ]]
    function p._aliases( item, lang )
    	local entity
    	if type(item)=='string' then -- "item" is a q-code
    		entity = mw.wikibase.getEntity(item); 
    	else
    		entity = item            -- "item" is the entity
    		item   = entity.id       -- look-up q-code
    	end
    	local s = {}
    	if entity and entity.aliases then						-- See if there is an entity and that is has aliases
    		if entity.aliases[lang] then						-- See if it has English Aliases
    			for i, j in pairs(entity.aliases[lang]) do		-- Make a loop around the English aliases
    				table.insert(s, j.value)					-- Create a table of English aliases
    			end
    		end
    	end
    	return s
    end
    
    -- ===========================================================================
    -- === Version of the functions to be called from template namespace
    -- ===========================================================================
    
    --[[
    getLabel
     
    This function returns a label translated to desired language, created based on wikidata
    
    Usage:
    {{#invoke:Wikidata label|getLabel|item=Q...|lang=..|link_style=..|capitalization=..}}
    
    Parameters
    	1: wikidata's item's q-code (required)
    	2: language (optional; default {{int:lang}} )
    	3: link_style: "wikipedia" (default), "Wikidata", "Commons", or "-" (no link)
    	4: capitalization - can be "uc", "lc", "ucfirst", "lcfirst"
    
    Error Handling:
    	Bad q-code will result in displayed error
    ]]
    function p.getLabel(frame)
    	local args = frame.args
    	if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then 
    		args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language 
    	end
    	if (not args.link) or (mw.text.trim(args.link) == "") then
    		args.link = "wikipedia"
    	end
    	if (not args.capitalization) or (mw.text.trim(args.capitalization) == "") then
    		args.capitalization = "none"
    	end
    	args.item = mw.text.trim(args.item or '')
    	return p._getLabel(args.item, args.lang, args.link, args.capitalization, args.show_id)
    end
    
    --[[
    sitelinks
    
    This function returns a comma separated list of sitelinks for a single project organized by language
    Its main purpose is to help with testing of _sitelinks function.
    
    Usage:
    {{#invoke:Wikidata label|sitelinks|item=Q...|project=..}}
    
    Inputs:
    	1: item - wikidata's item's q-code or entity class
    	2: project - "wikipedia" (or "wiki"), "wikisource", "wikiquote", "wikibooks", "wikinews", "wikiversity", "wikivoyage", "wiktionary", etc.
    
    Output:
    	comma separated list
    ]]
    function p.sitelinks(frame)
    	local sitelinks = p._sitelinks(frame.args.item, frame.args.project)
    	local s = {}
    	for i, j in pairs(sitelinks) do
    		table.insert(s, i .. ':' .. j)
    	end
    	return table.concat(s, ', ')	
    end
    
    --[[
    aliases
    
    This function returns a comma separated list of aliases for a single language
    Its main purpose is to help with testing of _aliases function.
    
    Usage:
    {{#invoke:Wikidata label|aliases|item=Q...|lang=..}}
    
    Inputs:
    	1: item - wikidata's item's q-code or entity class
    	2: lang - language code, like 'en' or 'de'
    
    Output:
    	Comma separated list of aliases
    ]]
    function p.aliases(frame)
    	return table.concat(p._aliases(frame.args.item, frame.args.lang), ', ')	
    end
    
    return p