ሞድዩል:Wikidata

ካብ ዊኪፐድያ፣ ናጻ ኢንሳይክሎፐድያ

Documentation for this module may be created at ሞድዩል:Wikidata/doc

--[[*********************************************************************************
	* Name: ሞድዩል:Wikidata
	*
	* Description: This module returns the value or values with or without format
    * specific to a Wikidata property.
	*
	* Last revision date: May 2, 2019.
	*
	* Status: In use.
	* Note: Adapted from es.wiki
	*********************************************************************************`-- ]]

local p = {}
local datequalifiers = {'P585', 'P571', 'P580', 'P582'}
local ti = mw.language.new('ti')
local first = true
--local mount Eye. mount should not be defined as local because doing so may fail.
 --[[ =========================================================================
			Error messages
	  ========================================================================= `-- ]]

local notices = {
	["errors"] = {
		["property-param-not-provided"] = "Property parameter not provided.",
		["entity-not-found"] = "Entry not found.",
		["unknown-claim-type"] = "Unknown notification type.",
		["unknown-snak-type"] = "Unknown data type.",
		["unknown-datavalue-type"] = "Unknown data format.",
		["unknown-entity-type"] = "Unknown input type.",
		["unknown-value-module"] = "You need to set both value parameters and function module value.",
		["value-module-not-found"] = "The module pointed to by value-module was not found.",
		["value-function-not-found"] = "The function pointed to by value-function was not found.",
		["other entity"] = "Links to different elements disabled."
	},
	["somevalue"] = "''unknown value''",
	["novalue"] = ""
}

-- Modules and functions used
local tableElement = require('Module:Tables').element
--
-- Modules in which the most common data types are defined if they are
-- different from Wikidata/Formats
--
local modulesTypes	=  {
	['height']		= 'Module:Wikidata/Magnitude format',
	['area']		= 'Module:Wikidata/Magnitude format',
	['flag']		= 'Module:Wikidata/Country formats',	
	['ዝተማህረ ኣብ']	= 'Module:Wikidata/Education formats',
	['image']		= 'Module:Wikidata/Image format',
	['place']		= 'Module:Wikidata/Place format',
	['placeFormat'] = 'Module:Wikidata/Place format',
	['magnitude']	= 'Module:Wikidata/Magnitude format',
	['movement']	= 'Module:Wikidata/Movement format',	
	['periodicity'] = 'Module:Wikidata/Magnitude format',
	['award']		= 'Module:Wikidata/Award format',
}

local modulesComplexTypes	=  {
	['ዜግነት']		= 'Module:Wikidata/Country formats',	
}

 --[[ =========================================================================
	  Function to pass the frame when used in other modules.	 
	 ========================================================================= `-- ]]
function p:setFrame(frame)
	mount = frame
end
 --[[ =========================================================================
	  Function to identify the item corresponding to the page or another given.
			  The latter does not work yet.	 
	 ========================================================================= `-- ]]

function EntitySelectionById( id )

		if id and id ~= ''  then
			return mw.wikibase.getEntityObject( id )
		else
			return mw.wikibase.getEntityObject()
		end

end

 --[[ =========================================================================
	  Function that identifies whether the returned value is an item or a property
	  and based on that add the corresponding prefix	
	 ========================================================================= `-- ]]

function EntitySelectionByValue( value )
	local prefix = ''
	if value['entity-type'] == 'item' then
		prefix = 'q' -- Item prefix
	elseif value['entity-type'] == 'property' then
		prefix = 'p' -- Property prefix
	else
		return errorFormat( 'unknown-entity-type' )
	end
	return prefix .. value['numeric-id'] -- The prefix and the numeric code are concatenated
end

 --[[ =========================================================================
	  Helper function for formatting error messages	 
	 ========================================================================= `-- ]]

function errorFormat( key )
	return '<span class="error">' .. notices.errors[key] .. '</span>'
end
 --[[ =========================================================================
	  Function to determine range	
	 ========================================================================= `-- ]]
function getRank(statementsTable)

	local rank = 'deprecated'

	for index, statement in pairs(statementsTable) do
		if statement.rank == 'preferred' then
			return 'preferred'
		elseif statement.rank == 'normal' then
			rank = 'normal'
		end
	end

	return rank
end

 --[[ =========================================================================
	  Function to determine the highest ranking statement or statements	
	 ========================================================================= `-- ]]
function p.filterStatementByRank(statementsTable)
	local rank = getRank(statementsTable)
	local helperTable = statementsTable
	statementsTable = {}

	for index, statement in pairs(helperTable) do
		if statement.rank == rank then
			table.insert(statementsTable, statement)
		end
	end
	return statementsTable
end

 --[[ =========================================================================
	  Function to select the type of statement: Reference, main value
      or qualifier	 
	 ========================================================================= `-- ]]

function statementSelection(statement, options)
	local source = {}
	local propertySource = {}
	local qualifier = options.qualifierFormat ~= '()' and options.qualifier

	if qualifier ~= '' and qualifier  and statement['qualifiers'] then
		if statement['qualifiers'][mw.ustring.upper(qualifier)] then
			return statement.qualifiers[mw.ustring.upper(qualifier)][1] -- returns the qualifier (will only return the first value)
		else
			return "" --So that it does not throw exception if the qualifier does not exist
		end
	elseif options.info == 'source' and statement['references'] then
		source = statement.references[1]['snaks']
		for k,v in pairs(source) do
			propertySource = k
		end
		return statement.references[1]['snaks'][propertySource][1]  -- returns the source (the table is left to roam)
	elseif (qualifier == '' or not qualifier) and (options.info ~= 'source') then
		return statement.mainsnak -- returns the main value
	else
		return ''	
	end
end

 --[[ =========================================================================
	  Function to collect statements	 
	 ========================================================================= `-- ]]

function p.getStatements(entityId)


	-- == We check that there is an item linked to the page in Wikidata ==
	if not pcall (EntitySelectionById, entityId ) then
		return false
	end
	local entity  = EntitySelectionById(entityId)

	if not entity then
		return  '' -- If the page is not linked to an item it does not return anything
	end

	-- == We check that the item has statements (claims) ==

	if not entity.claims then
		return '' -- If the item has no statements it does not return anything
	end
	-- == Format statement and clean concatenated ==

	return entity.claims
end

 --[[ =========================================================================
	  Function to create the string that the statement will return	
	 ========================================================================= `-- ]]
	
local function valinQualif(claim, qualifs)
	local claimqualifs = claim.qualifiers
	local i,qualif
	local vals, vals1, datavalue, value
	
	if not claimqualifs then
		return nil
	end
	for i, qualif in pairs(qualifs) do
		vals = claimqualifs[qualif]
		if vals then
			vals1 = vals[1]
			if vals1 then
				datavalue=vals1.datavalue
				
				if datavalue then
					value = datavalue.value
					
					if value then
						return value.time
					end
				end
			end
		end
	end
end	

function p.getProperty(options, statement)
	local property	 = {}
	
	-- Resolve property aliases
	if options.property == 'ትኽክልነት' or options.property == 'ማእገር' or options.property == 'ዝንግሪር'  then --latitude, longitude or precision
		--Earth
		property = 'P625'
		
		-- Moon
        if mw.wikibase.getEntityObject() and mw.wikibase.getEntityObject():formatPropertyValues("p376")["value"] == 'ወርሒ' then
	    	property = 'P8981'
        end 
	else
		property = options.property -- In the rest of the cases the given is read
	end

	if not property then -- We check if the given property exists and otherwise an error is returned
		return errorFormat( 'property-param-not-provided' )
	end
	local orderedTable
	if statement then
		orderedTable = statement
	elseif mw.wikibase.isValidEntityId(tostring(options.entityId)) and mw.wikibase.isValidEntityId(tostring(property)) then
			orderedTable = mw.wikibase.getAllStatements( options.entityId, mw.ustring.upper(property) )
			if not orderedTable[1] then return '' end
	else
		return ''
	end
	
	-- Function that separates the string 'inputstr' using a 'sep' separator
	function split(inputstr, sep) 
		sep=sep or '%s' 
		local t={}
		for field,s in string.gmatch(inputstr, "([^"..sep.."]*)("..sep.."?)") do 
			table.insert(t,field)  
			if s=="" then 
				return t 
			end 
		end 
	end
	
	-- Apply qualifier filter
	if (options.qualifierFilter ~= nil and options.qualifierFilter ~= '') then
		local opts = split(options.qualifierFilter, ';')
		local negative = false
		if (#opts > 2) then
			if (opts[3]=='n') then
				negative = true
			elseif (opts[3]=='p') then
				negative = false
			end
		end
		
		orderedTable = p.qualifiersFilter(orderedTable, opts[1], split(opts[2], ','))
	end
	
	-- Apply value filter
	if (options.valueFilter ~= nil and options.valueFilter ~= '') then
		local opts = split(options.valueFilter, ';')
		local negative = false
		if (#opts > 1) then
			if (opts[2]=='n') then
				negative = true
			elseif (opts[2]=='p') then
				negative = false
			end
		end
		
		orderedTable = p.valuesFilter(orderedTable, split(opts[1], ','), negative)
	end
	
	-- Apply format function
	local Module, feature
	feature = options['ዋጋ-ተግባር'] or options['value-function'] or options['feature']
	if feature then 
		Module = modulesComplexTypes[feature]
	
		if Module then
			return require(Module)[feature](orderedTable, options)
		end
	end	

	-- Prevent it from crashing when the find is done in options['textFormat'] if it is nil
	if not options['textFormat'] then
		options['textFormat'] = ''
	end

	--Leave in his case the highest ranking values
	if (options.highestRank == 'yes') then
		orderedTable = p.filterStatementByRank(orderedTable)
	end
	
	-- Sort by qualifier "order within series"
	if options.toOrder == 'yes' then
		require('Module:Tables').toOrder(orderedTable,
			function(element1,element2)
				local order1 = valinQualif(element1, { 'P1545' }) or '' -- element1.qualifiers.P1545[1].datavalue.value or ''
				local order2 = valinQualif(element2, { 'P1545' }) or '' -- element2.qualifiers.P1545[1].datavalue.value or ''
				
				return order1 < order2
			end
		 )
	end

	--Sort by date. See the chronosort function of :fr:Module:Wikidata/Récup
	if options.toOrder == 'ብዕለት' then
		require('Module:Tables').toOrder(orderedTable,
			function(element1,element2)
				local date1 = valinQualif(element1, datequalifiers) or '' -- element1.qualifiers.P580[1].datavalue.value.time or ''
				local date2 = valinQualif(element2, datequalifiers) or '' -- element2.qualifiers.P580[1].datavalue.value.time or ''
				
				return date1 < date2
			end
		 )
	end
	
	if not orderedTable[1] then
		return
	end

	-- == If you only want it to return a value ==
	-- Pending delete the parameter and replace it with a new value of the list=no parameter that would do the same as options.one = yes
	if options.one == 'yes' then -- To return the value of index 1
		orderedTable = {orderedTable[1]}
	elseif options.one == 'last' then -- To return the last entry in the table
		orderedTable = {orderedTable[#orderedTable]}
	end

-- == We create a table with the values that it will return ==

	local statementsFormat = {}
	local thereAreStatements
	
	for index, statement in pairs(orderedTable) do
   		formattedStatement = p.statementFormat(statement, options)
   		if formattedStatement and formattedStatement ~= '' then
		   	table.insert(statementsFormat, formattedStatement)
		   	thereAreStatements = true
	   	end	
   	end
   	
	first = true
	
	if not thereAreStatements then
		return
	end

	-- Format the list of values based on the list type of the
	-- options
	
	return p.listFormat(statementsFormat, options)
end

-- Function used to check if an entity has a property with a
-- specific value
-- Parameters:
--   · entity: wikidata entity table
--   · property: wikidata identifier for the property
--   · value: property value on Wikidata
function p.hasPropertyValue(entity, property, value)
	
	if entity and entity.claims and entity.claims[property] then
		
		local mainsnak
		
		for key,value in ipairs(entity.claims[property]) do
			if value and value.mainsnak then
				mainsnak = value.mainsnak
				if mainsnak.datatype == 'wikibase-item' and
						mainsnak.snaktype == 'value' and
						mainsnak.datavalue.value.id == value then
					return true
				end
			end
		end
	end
	
	return false
end

-- Function used to return the legend (P2096) of an image (P18) in Wikidata in a certain language
-- The function is called like this: {{#invoke:Wikidata |getImageCaption | <PARAMETER> | lang=<ISO-639code> |id=<QID>}}
-- Returns PARAMETER, unless it is equal to "FETCH_WIKIDATA", from the QID object (resource consuming call)
-- If QID is omitted or empty, the current article is used (call that does NOT consume resources)
-- If lang is omitted, the local language of the wiki is used by default, otherwise the language of the ISO-639 code
-- ISO-639 is documented here: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
-- The ranking is: 'preferred' > 'normal' and returns the label of the first image with ranking 'preferred'
-- Or the label of the first image with ranking 'normal' if there is no 'preferred'
-- Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua

p.getImageCaption = function(frame)
	-- search for a specific element in Wikidata (QID), otherwise it is nil
	local id = frame.args.id
	if id and (#id == 0) then
		id = nil
	end

	-- finds the language parameter that should contain a two-digit ISO-639 code
	-- if not declared, it defaults to the local language of the wiki (ti)
	local lang = frame.args.lang
	if (not lang) or (#lang < 2) then
		lang = mw.language.getContentLanguage().code
	end

	-- the first unnamed parameter is the local parameter, if declared
	local input_parm = mw.text.trim(frame.args[1] or "")
	if input_parm == "FETCH_WIKIDATA" or input_parm == "" or input_parm == nil then
		local ent = mw.wikibase.getEntityObject(id)
		local imgs
		if ent and ent.claims then
			imgs = ent.claims.P18
		end
		local imglbl
		if imgs then
			-- looks an image with ranking 'preferred'
			for k1, v1 in pairs(imgs) do
				if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
					local imglbls = v1.qualifiers.P2096
					for k2, v2 in pairs(imglbls) do
						if v2.datavalue.value.language == lang then
							imglbl = v2.datavalue.value.text
							break
						end
					end
				end
			end
			-- if there aren't any, looks for one with ranking 'normal'
			if (not imglbl) then
				for k1, v1 in pairs(imgs) do
					if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
						local imglbls = v1.qualifiers.P2096
						for k2, v2 in pairs(imglbls) do
							if v2.datavalue.value.language == lang then
								imglbl = v2.datavalue.value.text
								break
							end
						end
					end
				end
			end
		end
		return imglbl
	else
		return input_parm
	end
end

-- Function that returns the value of entity.claims[propertyId][occurrence].mainsnak.datavalue.value.text
-- with entity.claims[propertyId][occurrence].mainsnak.datavalue.value.language = 'ti'

-- Useful for getting property values of type monolingualtext

function p.getPropertyInTigrinya(idEntity, propertyId)
	-- See cs:Modul:Wikidata/item	formatEntityWithGender
	
	--
	local entity =  mw.wikibase.getEntityObject(idEntity)
	
	if not entity then
		return
	end
	
	local statement   = tableElement(entity,'claims', propertyId)
	
	if not statement then
		return
	end
	
	local value
	
	for k,v in pairs(statement) do
		value = tableElement(v,'mainsnak', 'datavalue', 'value')
		
		if value.language == 'ti' then
			return value.text
		end
	end
end

-- returns the id of the page in Wikidata (Q...), or nothing if the page is not connected to Wikidata
function p.pageId(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil else return entity.id end
end

function p.categorize(options, statement)
	-- Prevent it from crashing when the find is done in options['textFormat'] if it is nil
	if not options['textFormat'] then
		options['textFormat'] = ''
	end	
	
	local categoryOptions=options['መደብ']	
	
	if not categoryOptions then
		return ''
	end

	options['link'] = 'no'

	-- Create a table with property values.	
	local statementValues = {}

	if statement then
		statementValues = statement
	elseif options.property then
		local property = {}
		if options.property == 'ትኽክልነት' or options.property == 'ማእገር' or options.property == 'ዝንግሪር'  then
			property = 'P625' -- If we give the latitude, longitude or precision value, it will be equivalent to giving p625
		else
			property = options.property -- In the rest of the cases the given is read
		end
		
		if not p.getStatements(options.entityId) then
			return errorFormat( 'other entity' )
		elseif p.getStatements(options.entityId)[mw.ustring.upper(property)] then
			statementValues = p.getStatements(options.entityId)[mw.ustring.upper(property)]
		else
			return ''
		end		
	else
		return ''
	end

--  We create a table with each category from each value of the statement
	local categories	= {}
	local thereAreCategories
	
	if type(categoryOptions) == 'string' then
		local ModulePage = require('Module:Page')
	 
		for index, value in pairs(statementValues) do
			formattedValue = p.formatStatement(value, options)
			if formattedValue ~= '' then
				category = ModulePage.categoryExists(categoryOptions:gsub('$1',formattedValue))
			
				if category then
					table.insert(categories, category)
					thereAreCategories = true
				end
			end	
		end
	elseif type(categoryOptions) == 'table' then
		for index, value in pairs(statementValues) do
			category = categoryOptions[tableElement(value, 'mainsnak', 'datavalue', 'value', 'numeric-id')]
			
			if category then
				table.insert(categories, 'መደብ:' .. category)
				thereAreCategories = true
			end
		end
	end
	
	if thereAreCategories then
		return '[[' .. mw.text.listToText( categories, ']][[',']][[') .. ']]'
	end
	
	return ''
end

 --[[ =========================================================================
		Function that filters the values of a property and returns only those that
         have the qualifier "qualifier" indicated with one of the values "values"  
	 ========================================================================= `-- ]]
	 
function p.qualifiersFilter(t, qualifier, values, negative)
	local f = {}  -- Table to be returned with the filter result
	for k,v in pairs(t) do
		local counts = false
		if(v["qualifiers"] ~= nil and v["qualifiers"][qualifier] ~= nil) then
			for k2,v2 in pairs(v["qualifiers"][qualifier]) do
				-- Check if the identifier of the qualifier value is in the list
				for k3,v3 in pairs(values) do
					if (v2["datavalue"] ~= nil and v2["datavalue"]["value"] ~= nil and v2["datavalue"]["value"]["id"] ~= nil and v3 == v2["datavalue"]["value"]["id"])then  
						counts = true -- If it is mark as true
					end
				end
			end
		end
		if counts and not negative then -- If one of the qualifier values gave true, the element is inserted
			table.insert(f, v)
		elseif not counts and negative then -- If none of the qualifier values gave true, the element is inserted
			table.insert(f, v)
		end
	end
	return f
end

 --[[ =========================================================================
		Function that filters the values of a property and returns only those that
		have one of the values "values"  
	 ========================================================================= `-- ]]
	 
function p.valuesFilter(t, values, negative)
	local f = {}  -- Table to be returned with the filter result
	for k,v in pairs(t) do
		local counts = false
		if(v["mainsnak"]["datavalue"]["value"]["id"] ~= nil) then
			for k2,v2 in pairs(values) do
				if (v2 == v["mainsnak"]["datavalue"]["value"]["id"])then  
					counts = true -- If it is mark as true
				end
			end
		end
		if counts and not negative then -- If one of the qualifier values gave true, the element is inserted
			table.insert(f, v)
		elseif not counts and negative then -- If none of the qualifier values gave true, the element is inserted
			table.insert(f, v)
		end
	end
	return f
end

 --[[ =========================================================================
		Function that checks if the page is linked to Wikidata
        if it is, pass the value as an argument to the formatSnak function()  
	 ========================================================================= `-- ]]

function p.statementFormat( statement, options)
	if not statement.type or statement.type ~= 'statement' then -- It is verified that it has a type value and that this is a statement which happens whenever the property exists
		return errorFormat( 'unknown-claim-type' ) -- If it is not fulfilled, it returns an error
	end
	
	-- If there is a qualifier, it is returned to the right of the value of the
	-- statement in parentheses.
	
	local qualifying = options.qualifying or options.qualifier

	if qualifying and statement.qualifiers then
		-- At the moment the qualifiers, normally years, are not linked
	   local qualifyingOptions = {['textFormat']='', link='no', ['dateFormat']='ዓመት'} -- Pending
	  
	   local wQualifyingValue
	   local wQualifyingValueFormatted
	  
	   local qualifyingFunction, errorMessage = getFeature(qualifying, options['qualifying module'])
	  
		if errorMessage then
			return errorMessage
		elseif qualifyingFunction then
	   	  -- Use the received function on all qualifiers
	   	  wQualifyingValue		   = statement.qualifiers
		  wQualifyingValueFormatted = qualifyingFunction(wQualifyingValue, qualifyingOptions)
	   	elseif options.qualifierFormat and options.qualifierFormat == '()' then
			wQualifyingValue = statement.qualifiers[mw.ustring.upper(qualifying)]
			if wQualifyingValue and wQualifyingValue[1] then
				wQualifyingValueFormatted = p.dataFormat(wQualifyingValue[1], qualifyingOptions)
			end
		elseif options.qualifierFormat and table.getn(mw.text.split(options.qualifierFormat, '%.')) == 2 then
			formatQualifierModule = mw.text.split(options.qualifierFormat, '%.')
			formatted = require ('Module:' .. formatQualifierModule[1])
			if not formatted then
				return errorFormat( 'value-module-not-found' )
			end
			fun = formatted[formatQualifierModule[2]]
			if not fun then
				return errorFormat( 'value-function-not-found' )
			end
			
			if mw.ustring.find(options['textFormat'],'uppercase', plain ) and
			   (first or (options['separator'] and options['separator'] ~= 'null') or
			   	(options['list'] and options['list'] ~= '')) then
			  options['uppercase'] = 'yes'
				  first = false
			end
			
			if mw.ustring.find(options['textFormat'],'italics', plain ) then
				entityOptions.italics = 'yes'
			end
			
			wQualifyingValueFormatted = fun( statement.qualifiers, options, mount)
			--return require('Module:Tables').tostring(statement)
		else
	   	  -- Use the first value of the qualifier of the property received
	   	  wQualifyingValue = statement.qualifiers[mw.ustring.upper(qualifying)]
	   	 
	   	  if wQualifyingValue and wQualifyingValue[1] then
			wQualifyingValueFormatted = p.dataFormat(wQualifyingValue[1], qualifyingOptions)
		  end
		end
		if options.qualifierseparator then separator = options.qualifierseparator else separator = ' ' end
		if wQualifyingValueFormatted then
			formattedData = p.dataFormat(statement.mainsnak, options)
			return (formattedData and formattedData .. '&nbsp;<small>(' .. wQualifyingValueFormatted .. ')</small>') or nil
		end		
	end

	-- If there is no qualifying.
	return p.dataFormat(statementSelection(statement, options), options, statement.qualifiers)
end

 --[[ =========================================================================
		Function that checks the data type (snaktype)
		if it is value, it passes the value as an argument to the dataValueFormat function()	
	 ========================================================================= `-- ]]

function p.dataFormat( info, options, qualifyings)
	
	if not info or info == '' then
		return ''
	end
	if info.snaktype == 'somevalue' then
		-- Earliest date
		if qualifyings then
			if qualifyings['P1319'] and qualifyings['P1319'][1] and
			   qualifyings['P1319'][1].datavalue and
			   qualifyings['P1319'][1].datavalue.type=='time' then
			   	
				local dateOptions={['dateFormat']=options['dateFormat'],link=options.link}
		
				return 'post. ' .. require('Module:Wikidata/Date').FormatDateTime(qualifyings['P1319'][1].datavalue.value, dateOptions)
			end
		end
		
		-- If it does not have a valid qualifier
		return notices['somevalue'] -- Unknown value
	elseif info.snaktype == 'novalue' then
		return notices['novalue'] -- No value
	elseif info.snaktype == 'value' then
		return dataValueFormat( info.datavalue, options, qualifyings) -- If it has the data type, the value is passed to the dataValueFormat function()
	else
		return errorFormat( 'unknown-snak-type' ) -- Unknown data type
	end
end

 --[[ =========================================================================
	   Function that sets the format type based on the value type
       (dataValue.type) and in case a complementary format is requested associates
       the module where the format is set and its function that sets it	
	 ========================================================================= `-- ]]

function dataValueFormat( dataValue, options, qualifyings)
	local feature, errorMessage = getFeature(options['ዋጋ-ተግባር'] or options['value-function'] or options['feature'], options['value-module'] or options['Module'])
	
	if errorMessage then
		return errorMessage
	elseif feature then
		local entityOptions = {}
		
		for k, v in pairs(options) do
			entityOptions[k] = v
		end
		
		if mw.ustring.find(options['textFormat'],'uppercase', plain ) and
		   (first or (options['separator'] and options['separator'] ~= 'null') or
		   	(options['list'] and options['list'] ~= '')) then
		  entityOptions['uppercase'] = 'yes'
			  first = false
		end	
		
		if mw.ustring.find(options['textFormat'],'italics', plain ) then
			entityOptions.italics = 'yes'
		end
		
		return feature(dataValue.value, entityOptions, mount, qualifyings)		
	end

	-- == Default formats depending on the type of value ==

--		  * For coordinate type when given as property value: latitude, longitude or precision

	if options.property == 'ማእገር' then
		return dataValue.value['latitude']
	elseif options.property == 'ዝንግሪር' then
		return dataValue.value['longitude']
	elseif options.property == 'ትኽክልነት' then
		return dataValue.value['precision']

--		   * With the rest of the property

	elseif dataValue.type == 'wikibase-entityid' then	-- Type: Entity number that can be an item or property
		local entityOptions = {}
		if mw.ustring.find(options['textFormat'],'uppercase', plain ) and
		   (first or (options['separator'] and options['separator'] ~= 'null') or
		   	(options['list'] and options['list'] ~= '')) then
		  entityOptions['uppercase'] = 'yes'
			  first = false
		end
		entityOptions.link		 = options.link
		entityOptions.label	   = options.label
		entityOptions['itMustExist'] = options['itMustExist']
		
		if mw.ustring.find(options['textFormat'],'italics', plain ) then
			entityOptions.italics = 'yes'
		end
		return p.entityIdFormat( EntitySelectionByValue( dataValue.value ), entityOptions)
	elseif dataValue.type == 'string' then			   -- Type: Text string
		return dataValue.value
	elseif dataValue.type == 'url' then	 --URL type (web address)
		return value.url
	elseif dataValue.type == 'time' then				 -- Type: Date/time
		local dateOptions={['dateFormat']=options['dateFormat'],link=options.link}
	  
		if mw.ustring.find(options['textFormat'] or '','uppercase', plain ) and first then
			dateOptions['uppercase']='yes'
		end
		
		return require('Module:Wikidata/Date').FormatDateTime(dataValue.value, dateOptions, qualifyings)
	elseif dataValue.type == 'monolingualtext' then	   -- Type: monolingual
		if dataValue.value then
			if options.language then
				for k, v in pairs(dataValue) do
					if v.language == options.language then
						return v.text
					end
				end
			else
				return dataValue.value.text
			end
		else
			return ''
		end
	elseif dataValue.type ==  'quantity' then			-- Type: Quantity
		return require('Module:Wikidata/Formats').unitFormat(dataValue, options)
	elseif  dataValue.value['latitude']  and dataValue.value['longitude'] then -- Type: Coordinates
		local globe = require('Module:Wikidata/Globes')[dataValue.value.globe]

--We concatenate the latitude and longitude values within the Coord template

		if globe ~= 'earth' then
			return  mount:preprocess('{{coord|' .. dataValue.value['latitude'] .. '|' ..
				   dataValue.value['longitude'] .. '|globe:' .. globe .. '_type:' .. options.kind .. '|display=' ..
				   options.display ..'|format=' .. options.format..'}}')
		else
			return  mount:preprocess('{{coord|' .. dataValue.value['latitude'] .. '|' ..
				   dataValue.value['longitude'] .. '|type:' .. options.kind .. '|display=' ..
				   options.display ..'|format=' .. options.format..'}}')
		end

	else
		return errorFormat( 'unknown-datavalue-type' ) -- If it is not one of these types, it will return an unknown value error
	end
end

  --[[ =========================================================================
		  We format internal links	
	   ========================================================================= `-- ]]

-- Options:
--	 - link:		Possible values 'yes' or 'no'
--	 - uppercase:		Possible values 'yes' or 'no'
--	 - italics:		Possible values 'yes' or 'no'

function p.entityIdFormat(idEntity, options)
	local link   = mw.wikibase.sitelink(idEntity)
	local label = mw.wikibase.label(idEntity)
	return require('Module:Wikidata/Formats').toLink(link, label, idEntity, options)
end

 --[[ =========================================================================
		Principal function	
	 ========================================================================= `-- ]]

function p.Wikidata( frame )
	mount = frame
	local args = frame.args
	
	if args.value == 'no' then
		return
	end

	local parentArgs = frame:getParent().args
	
	-- Copy the arguments
	local arguments = {}
	
	for k, v in pairs(args) do
		arguments[k] = v
	end
	
	for k, v in pairs(parentArgs) do
		if not arguments[k] then
			arguments[k] = v
		end
	end
	
	--if true then return require('Module:Tables').tostring(arguments) end
	
	-- Do not generate the Wikidata value if a local value has been provided and
	-- the local value is a priority.
	local wikidataValue;
	if (args.priority ~= 'yes' or (args.import and args.import == 'no')) and args.value and args.value ~= '' then
		wikidataValue = '';
	else
		local ent = EntitySelectionById(arguments.entityId)
		arguments.entityId = ent and ent.id or nil
		wikidataValue = p.getProperty(arguments, nil);
	end
	
 	local categories = '';
 	local namespace = frame:preprocess('{{NAMESPACENUMBER}}');
 	
 	if (namespace == '0' and (not args.categories or args.categories ~= 'no') and
 			args.property and string.upper(args.property) ~= 'P18' -- P18: Commons image
 			and string.upper(args.property) ~= 'P41' -- P41: flag image
 			and string.upper(args.property) ~= 'P94' -- P94: coat of arms image
 			and string.upper(args.property) ~= 'P109' -- P109: signature of person
 			and string.upper(args.property) ~= 'P154') then -- P154: logo
	 	if wikidataValue ~= '' and args.value and args.value ~= '' then
	 		categories = '[[መደብ:ዊኪፐድያ:Articles with local data]]'
	 	elseif wikidataValue and wikidataValue == '' and args.value and args.value ~= '' and
	 		(not args.qualifier or args.qualifier == '') and
	 		(not args.info or args.info == '' or args.info ~= 'source')then
	 		categories = '[[መደብ:ዊኪፐድያ:Articles with data to transfer to Wikidata]]'
	 	end
	end

	if args.priority == 'yes' and wikidataValue  ~= '' then -- If the value yes is given to priority, the value of Wikidata will take precedence
		if args.import and args.import == 'no' and args.value and args.value ~= '' then
			return args.value .. categories
		elseif wikidataValue then
			return wikidataValue .. categories -- value that replaces the value of Wikidata parameter 2
		else
			return categories
		end
	elseif args.value and args.value ~= '' then
		 return args.value .. categories
	elseif args.import and args.import == 'no' then
		 return ''
	elseif wikidataValue then -- If the value is nil an exception is thrown when concatenating
		return wikidataValue .. categories
	else
		return ''
  end 
end

function getFeature(feature, moduleName)
	if not feature then
		return
	elseif type(feature) == 'function' then -- Use from LUA
		return feature
	elseif feature == '' or not moduleName or moduleName == '' then
		return
	else -- Use from a template
		local Module
		
		if not moduleName or moduleName == '' or moduleName == 'Wikidata/Formats' then
			Module = require(modulesTypes[feature] or 'Module:Wikidata/Formats')
		else
			Module = require ('Module:' .. moduleName)
		end
		
	   	if not Module then
		   	return nil, errorFormat( 'value-module-not-found' )
		elseif not Module[feature] then
		   	return nil, errorFormat( 'value-function-not-found' )
		else
		   	return Module[feature]
	   	end
	end
end

function p.addLinkback(propertyValue, idEntity, propertyId)
	local lidEntity
	
	if propertyValue and propertyId then
		lidEntity= (idEntity ~='' and idEntity) or mw.wikibase.getEntityIdForCurrentPage()
	end

	if lidEntity then
		return propertyValue .. '<span class=\"wikidata-link noprint\"> [[ፋይል:Blue_pencil.svg|ሓበሬታ ኣብ ዊኪዳታ ርኣይን ኣመሓይሽን|10px|baseline|alt=ሓበሬታ ኣብ ዊኪዳታ ርኣይን ኣመሓይሽን|link=https://www.wikidata.org/wiki/' .. lidEntity .. '?uselang=ti#' .. propertyId ..
		 ']]</span>'
	else
		return propertyValue
	end
end

function p.listFormat(board, options)
	if not board or not board[1] then
		return
	end
	
	local list_type = options.list
	local pencil
	
	if options.linkback == 'yes' and options.entityId and options.property then
		pencil = '<span class=\"wikidata-link noprint\"> [[ፋይል:Blue_pencil.svg|ሓበሬታ ኣብ ዊኪዳታ ርኣይን ኣመሓይሽን|10px|baseline|alt=ሓበሬታ ኣብ ዊኪዳታ ርኣይን ኣመሓይሽን|link=https://www.wikidata.org/wiki/' .. options.entityId .. '?uselang=ti#' .. options.property ..
		 ']]</span>'
	else
		pencil = ''
	end
	
	if not board[2] then
		-- If the table only has one element, return it
		return board[1] .. pencil
	end
	
	if list_type == 'not ordered' or list_type == 'ordered' or list_type == 'nobullet' then
		local list = mw.text.listToText( board, '</li><li>', '</li><li>' )
		
		if list_type == 'not ordered' then
			return '<ul><li>' .. list .. pencil .. '</li></ul>'
		elseif list_type == 'ordered' then
			return '<ol><li>' .. list .. pencil .. '</li></ol>'			
		else
			return '<ul style="list-style-type:none;list-style-image:none;margin-left:0;padding-left:0"><li>' .. list .. pencil .. '</li></ul>'
		end
	else
		local separators = {
			[''] = '',
			['፣'] = '፣ ',
			['null'] = '፣ ',
			['no'] = ''
		}
		local conjunctions = {
			[''] = '',
			['ከምኡ’ውን'] = ' ከምኡ’ውን ',
			['ወይ'] = ' ወይ ',			
			['null'] = ' ከምኡ’ውን ',
			['no'] = ''
		}
		
		local separator = options.separator
		local conjunction = options['conjunction']
		
		if not separator then
			separator = '፣ '
		else
			separator = separators[separator] or separator
		end
		
		if not conjunction then
			conjunction = ' ከምኡ’ውን '
		else
			conjunction = conjunctions[conjunction] or conjunction
		end
		
		if conjunction == ' ከምኡ’ውን ' and mount and board[2] then 
		end
		
		return mw.text.listToText( board, separator, conjunction ) .. pencil
	end
end

-- Existing functions in other modules
function p.getWikidataLabel(entity, fallback)
	if not entity then entity = fallback end
	if entity and entity.labels and entity.labels.ti then
		return entity.labels.ti.value
	end
end

function p.getWikidataImage(entity, property)
	local image, imageValue, imageFooters, k, imageFooter
	if not entity then
		return
	end
	
	--  Get the first Wikidata image of the person
	local image = tableElement(entity, 'claims', property, 1)
--[[	
	-- Get the image object, either first, last (WIP) or by date (WIP)
	local image = (function()
		local ImagenObj = tableElement(entity, 'claims', propertyId)
		if options.toOrder == 'ብዕለት' then
			--
		end

		return tableElement(ImagenObj, 1)
	end)()
--]]
	if not image then
		return
	end
	imageValue =  tableElement(image, 'mainsnak', 'datavalue', 'value')
	imageFooters =  tableElement(image, 'qualifiers', 'P2096')
	-- Find footer in Tigrinya
	if imageFooters then
		for k,imageFooter in pairs(imageFooters) do
			if imageFooter.datavalue.value.language == 'ti' then
				return imageValue, imageFooter.datavalue.value.text
			end
		end
	end
	-- If there is no footer in tigrinya, check if there is a specified date for the image
	imageFooters = tableElement(image, 'qualifiers', 'P585')
	if imageFooters and imageFooters[1] then
		return imageValue, 'ኣብ ' .. require('Module:Wikidata/Date').FormatDateTime(imageFooters[1].datavalue.value, {['dateFormat']='ዓመት',['link']='no'})
	end
	-- No footer in Tigrinya
	return imageValue
end

function p.property(entity, propertyId, options)
	if entity and entity.claims and entity.claims[propertyId] then
		if not options then
			options = {['linkback']='yes'}
		end
		--[[
		local PositionalValue = (function()
			if options['positional_value'] == 'last' then return -1 end
			if type(options['positional_value']) == 'number' then return options['positional_value'] end
			return 1
		end)()

		local PositionalValueQualifier =(function()
			if options['positional_value_qualifier'] == 'last' then return -1 end
			if type(options['positional_value_qualifier']) == 'number' then return options['positional_value_qualifier'] end
			return 1
		end)()
		
		local Qualifier = options['qualifier']

		local Obj = (function()
			local Obj = (function()
				local Obj = tableElement(entity, 'claims', propertyId)
				if PositionalValue == -1 then return tableElement(Obj, #Obj) end
				return tableElement(Obj, PositionalValue)
			end)()

			if Qualifier then
				Obj = (function()
					local Obj = tableElement(Obj, 'qualifiers', Qualifier)
					if PositionalValueQualifier == -1 then return tableElement(Obj, #Obj) end
					return tableElement(Obj, PositionalValueQualifier)
				end)()
			end
			return Obj
		end)()
		
		Type	= tableElement(Obj, 'datavalue', 'type')
		
		-- Return the entity ID, for entity properties
		if options['form'] == 'entityID' then
			return tableElement(Obj, 'datavalue', 'value', 'id')
		end
		
		-- Prepare to return the most recent file in the property. Find out how to do it with qualifiers
		if options['form'] == 'ፋይል' then
			if Qualifier then return tableElement(Obj, 'datavalue', 'value') end
			if not options['one'] then options['one'] = 'last' end
			options['toOrder'] = 'ብዕለት'
		end

		-- Get property as raw string
		if options['form'] == 'ገመድ' then
			options['linkback'] = 'no'
			if Type == 'string' then
				return tableElement(Obj, 'datavalue', 'value')
			end
		end

		-- Return a correctly formatted numeric string
		if options['form'] == 'ቍጽሪ' then
			if Type == 'quantity' then
				return numberFormat(tableElement(Obj, 'datavalue', 'value', 'amount'))
			end
		end

		-- Return a numeric string with its unit
		if options['form'] == 'ኣሃዱ' then
			if tableElement(entity, 'claims', propertyId, 2, 'mainsnak', 'datavalue') then
				return numberFormat(tableElement(entity, 'claims', propertyId, 1, 'mainsnak', 'datavalue', 'value', 'amount')) .. '&nbsp;-&nbsp;' .. unitNumber(tableElement(entity, 'claims', propertyId, 2, 'mainsnak', 'datavalue'), options)
			else
				return unitNumber(tableElement(entity, 'claims', propertyId, 1, 'mainsnak', 'datavalue'), options)
			end
		end
		--]]
		
		options.entityId  = entity.id
		options.property = propertyId
		
		return p.getProperty(options, entity.claims[propertyId])
	end
end

function p.isAValue(entity, propertyId, idSearch)
	if not entity or not propertyId then
		return false
	end
	
	local statement = tableElement(entity, 'claims', propertyId)
	local idSearched
	if not statement then
		return false
	end

	for k,v in pairs(statement) do
		idSearched = tableElement(v,'mainsnak','datavalue','value','id')
		if idSearched == idSearch then
			return true
		end
	end
	return false
end

-- Get the object mw.language, to use its functions in other modules
function p.language()
	return ti
end

return p