Jump to content

Module:Wp/khw/Wikidata2

From Wikimedia Incubator

Documentation for this module may be created at Module:Wp/khw/Wikidata2/doc

-- Den ordning fallback language hämtas, om svensk label saknas. Engelska först, därefter bokmål, danska, etc...
-- local fallback = {'en', 'nb', 'da', 'nn', 'de', 'fr', 'es', 'it', 'pt'}
local formatera = require('Module:Wp/khw/Math')
local i18n = {
	["errors"] = {
		["property-param-not-provided"] = "Property parameter not provided.",
		["entity-not-found"] = "Entity not found.",
		["unknown-claim-type"] = "Unknown claim type.",
		["unknown-snak-type"] = "Unknown snak type.",
		["unknown-datatype"] = "Unknown datatype.",
		["unknown-entity-type"] = "Unknown entity type.",
		["unknown-value-module"] = "You must set both value-module and value-function parameters.",
		["unknown-claim-module"] = "You must set both claim-module and claim-function parameters.",
		["value-module-not-found"] = "The module pointed by value-module not found.",
		["value-function-not-found"] = "The function pointed by value-function not found.",
		["claim-module-not-found"] = "The module pointed by claim-module not found.",
		["claim-function-not-found"] = "The function pointed by claim-function not found."
    },
	["noarabiclabel"] = "زمرہ:ویکی ڈیٹا صفحات مع غیر موجود اردو نشانات",
	["warnDump"] = "[[زمرہ:Called function 'Dump' from module Wikidata]]",
	["somevalue"] = "", --''نامعلوم''
	["novalue"] ="",--نا معلوم قیمت
	["cateref"] ="[[زمرہ:صفحات مع ویکی ڈیٹا حوالہ جات]]"
}
local sortingproperties = {'P585','P571','P580','P569','P582','P570'}

function catewikidatainfo(options)
	local prop = options.property
	local catewikidatainfo = ' [[زمرہ:ویکی ڈیٹا کے مواد کا ستعمال کرنے والے صفحات|'.. (prop or 'wikidata')..']]'
	if (not options.nolink or options.nolink == '') 
		then return catewikidatainfo else return ''
	end
end

function versalisering(label, options)
	local versalisering = options.versalisering
	if options.firstversalisering and options.num == 1 then 
		versalisering = options.firstversalisering
	end
	if not versalisering or versalisering == '' then
		return label
	end
	if versalisering == 'lcfirst' then
		return mw.getCurrentFrame():preprocess("{{lcfirst: " .. label .. " }}")
	elseif versalisering == 'ucfirst' then
		return mw.language.getContentLanguage():ucfirst( label )
	elseif versalisering == 'lc' then
		return mw.getCurrentFrame():preprocess("{{lc: " .. label .. " }}")
	elseif versalisering == 'uc' then
		return mw.getCurrentFrame():preprocess("{{uc: " .. label .. " }}")
	end
	return label
end

function getqualifierbysortingproperty(claim, sortingproperty)
	for k, v in pairs(sortingproperty) do
		if claim.qualifiers and claim.qualifiers[v] and claim.qualifiers[v][1].snaktype == 'value' then
			return claim.qualifiers[v][1].datavalue.value.time 
		end
	end
	return nil
end

function getDate(claim, options)
	local sortingproperty = sortingproperties
	if type(options.sortingproperty) == 'table' then
		sortingproperty = options.sortingproperty
	elseif type(options.sortingproperty) == 'string' then
		sortingproperty = {options.sortingproperty}
	end
	return getqualifierbysortingproperty(claim, sortingproperty) 
end

function getDateArb(claim, options)
	local sortingproperty = options.sortingproperty or 'P569'
	if claim.mainsnak.snaktype == 'value' then
		local item = claim.mainsnak.datavalue.value['numeric-id']
		if claim.mainsnak.datavalue.value['entity-type'] == 'item' then
			item = 'Q' .. item
		elseif claim.mainsnak.datavalue.value['entity-type'] == 'property' then 
			item = 'P' .. item
		end
		return formatStatements({property = sortingproperty, entityId = item, enbarten = 'true', sortbytime = 'chronological', noref = 'true'})
	end
end

function descriptionIn(langcode,id) -- returns item description for a given language
	local lan = langcode or 'khw'
	local entity = mw.wikibase.getEntityObject(id)
		if entity
		and entity.descriptions 
		and entity.descriptions[''..lan..'']
		and entity.descriptions[''..lan..''].value 
		then
			local lang = entity.descriptions[''..lan..'']
			if lang['language'] == lan then
			return entity.descriptions[''..lan..''].value
			else return nil end
		end
end

function labelIn(langcode,id) -- returns item label for a given language
	local lan = langcode or 'khw'
	local entity = mw.wikibase.getEntityObject(id)
		if entity
		and entity.labels 
		and entity.labels[''..lan..'']
		and entity.labels[''..lan..''].value 
		then
			local lang = entity.labels[''..lan..'']
				if lang['language'] == lan then
				return entity.labels[''..lan..''].value
				else return nil end
		end
end

function comparedates(a, b)  -- returns true if a is earlier than B or if a has a date but not b
	if a and b then
		return a > b
	elseif a then
		return true
	end
end

function sortbyqualifier(claims, options)
	table.sort(claims, function(a,b)
		local timeA = getDate(a, options)
		local timeB = getDate(b, options)
		if options.sortbytime == 'inverted' then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function sortbyarb(claims, options)
	table.sort(claims, function(a,b)
		local timeA = getDateArb(a, options)
		local timeB = getDateArb(b, options)
		if options.sortbyarbitrary == 'inverted' then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function Labelfunction( entityId, label ,labeloption , options) -- label with no arwiki sitelink
	local jlabel =versalisering(label, options) -- The label
	local ar = labelIn('khw',entityId ) -- The arabic label
	local arlabel = versalisering(ar, options) 
	if labeloption and labeloption ~= '' then
			jlabel = labeloption 
	elseif options.illwd2  and options.illwd2  ~= '' then
		if arlabel and arlabel ~= '' then
			jlabel = mw.getCurrentFrame():expandTemplate{ title = 'Ill-WD2', args = {arlabel, id=entityId, noWD='y'} }
			else 
			jlabel  = mw.getCurrentFrame():expandTemplate{ title = 'Ill-WD2', args = {id=entityId, en='y', noWD='y'} }
		end
		
	elseif options.enlabelcate and options.enlabelcate  ~= '' then
			if not arlabel or arlabel == '' then
				jlabel =versalisering(label, options)
				 if jlabel and jlabel ~= '' then
				 jlabel = jlabel ..' [['.. i18n.noarabiclabel ..'|'.. entityId ..']]'
			end end
			
	else--if options.justarabic and options.justarabic  ~= '' then
			if arlabel and arlabel ~= ''
				then jlabel = arlabel
				else jlabel = nil
			end
	end
	if jlabel and jlabel ~= ''
	then
	return jlabel.. catewikidatainfo(options)
	end
end
function getEntityFromId( id )
	if id then 
		return mw.wikibase.getEntityObject( id )
	else
		return mw.wikibase.getEntityObject() 
	end
end
 
function getEntityIdFromValue( value )
    if value['entity-type'] == 'item' then
        return 'Q' .. value['numeric-id']
    elseif value['entity-type'] == 'property' then
        return 'P' .. value['numeric-id']
    else
        return formatError( 'unknown-entity-type' )
    end
end
 
function formatError( key )
    return i18n.errors[key]
end
 
function formatStatements( options, ref )
   	local formattedStatements = {}
   	local claims = {}
   	if not options.property then return formatError( 'property-param-not-provided' ) end

    if type(ref) == 'table' then -- för de fall där funktionen anropas och alla claims redan finns i en tabell
		claims = ref[options.property] or {}
	else
    	--Get entity
    	local entity = nil
    	if options.entity and type( options.entity ) == "table" then
        	entity = options.entity
    	else
        	entity = getEntityFromId( options.entityId )
    	end
 
    	if not entity then return '' end --TODO error? 
    	if not entity.claims or not entity.claims[options.property:upper()] then
        	return '' --TODO error?
    	end
 
    	--Format statement and concat them cleanly
		if options.rank == 'best' or not options.rank then 
			claims = entity:getBestStatements( options.property:upper() )
			elseif options.rank == 'valid' then
				for i, statement in pairs( entity.claims[options.property:upper()] ) do
		    		if statement.rank == 'preferred' or statement.rank == 'normal' then
	    				table.insert( claims, statement )
	    			end
				end
			elseif options.rank == 'all' then
				for i, statement in pairs( entity.claims[options.property:upper()] ) do
					table.insert( claims, statement )
				end
		else
			for i, statement in pairs( entity.claims[options.property:upper()] ) do
				if statement.rank == options.rank then
					table.insert( claims, statement )
				end
			end
		end
		if options.avoidqualifier then  -- to avoid value with a given qualifier
			local claims2 = {}
			for i, statement in pairs( claims ) do	
				if not statement.qualifiers or not statement.qualifiers[options.avoidqualifier:upper()] then
					table.insert( claims2, statement)
				end
			end
			claims = claims2
		end
		--om det finns vissa statements som har en qualifier som säger "språk = svenska", ta bara med dessa
		--alternativt om det finns statements som har en qualifier som säger "skriptsystem == latinska alfabetet"
		if not options.langpref or options.langpref == '' then
			local claims2 = {}
			for i, statement in pairs( claims ) do
				if statement.qualifiers and statement.qualifiers.P407 then
					for k, v in pairs( statement.qualifiers.P407 ) do
						if v.snaktype == 'value' and v.datavalue.value['numeric-id'] == 13955 then -- Q1617 = 'اردو'
							table.insert( claims2, statement )
						end
					end
				elseif statement.qualifiers and statement.qualifiers.P282 then
					for k, v in pairs( statement.qualifiers.P282 ) do
						if v.snaktype == 'value' and v.datavalue.value['numeric-id'] == 8196 then -- Q209468 = 'اردو حروف تہجی'
							table.insert( claims2, statement )
						end
					end
				end
			end
			if #claims2 > 0 then
				claims = claims2
			end
		end
		if options.sortbytime == 'chronological' or options.sortbytime == 'inverted' then
			claims = sortbyqualifier(claims, options)
		elseif options.sortbyarbitrary == 'chronological' or options.sortbyarbitrary == 'inverted' then
			claims = sortbyarb(claims, options)
		end
	end
	if options.enbarten and options.enbarten ~= '' and #claims > 1 then
		claims = {claims[1]}
	end
	local statementsraw = {}
	if claims then
		for i, statement in pairs( claims ) do
			options.num = i
			local stat = formatStatement( statement, options )
			if stat then
				
				local s = stat.value
				local d = stat.datum
				local tf = stat.tifr
				local awardqual = stat.foto
				local pr = stat.pr
				local utgivort = stat.utgivort
				local ro = stat.ro
				local qp1a = stat.qp1a
				local onlyqualifier = stat.onlyqualifier
				local qp1 = stat.qp1
				local qp2 = stat.qp2
				local qp3 = stat.qp3
				local qp4 = stat.qp4
				local qp5 = stat.qp5

				local amatch =stat.amatch
				local reff  =stat.reff
				local goal =stat.goal

				local start2 = stat.start1
				local finish2 = stat.finish1
				local before2 = stat.before1
				local after2 = stat.after1
				local constituency2 = stat.constituency1
				local series2 = stat.series1
				local electedin2 = stat.electedin1
				local P1001 = stat.pp1001
				local P108 = stat.pp108
				local P642  = stat.pp642

				if s == '' then s = nil end
				if s then
		if reff and options.reff and options.reff ~= ''  then
			s= s .. reff
		end
			if options.template and options.template ~= '' then
					s = mw.getCurrentFrame():expandTemplate{ title = options.template 
						, args ={stat.QQ1
							,s
							,stat.QQ2
							,stat.QQ3
							,stat.QQ4
							,stat.QQ5
							,stat.QQ6
							,stat.QQ7
							,stat.QQ8
							,stat.QQ9
							,stat.QQ10} }
			end
			if options.football and options.football ~= '' then
				s =mw.getCurrentFrame():expandTemplate{ title = "صندوق معلومات سيرة كرة قدم/سطر فريق", args = {(start2 or ''),(finish2 or '') ,s,amatch,goal } }
			end
			
			if options.office and options.office ~= '' then
				s = mw.getCurrentFrame():expandTemplate{ title = "معلومات صاحب منصب/منصب ويكي بيانات/نواة", args = 
				{office = s, 
				termstart = start2, 
				termend = finish2, 
				constituency = constituency2, 
				predecessor = before2, 
				successor = after2, 
				series= series2,
				of=P642,
				electedin=electedin2,
				jurisdiction=P1001,
				employer=P108,
				entityId=options.entityId} } 
		end
		
	function qoo(Prefix,qualpref,p,Suffix)
		if p and p ~='' then 
		return mw.text.tag('small', {}, (Prefix or ' (').. (qualpref or '') .. p .. (Suffix or ')'))  end
	end
			QPrefix = options.qualifierprefix
			QSuffix = options.qualifiersuffix
		if qp1 and qp1 ~='' and options.qual1 and options.qual1 and qp1a and options.qual1a and options.qual1a ~= ''
		then
			s = s .. qoo(QPrefix, options.qual1pref, qp1, QSuffix) .. qoo(QPrefix, options.qp1apref, qp1a, QSuffix)
		elseif qp1 and qp1 ~='' and options.qual1 and options.qual1 ~= '' then
			s = s .. qoo(QPrefix, options.qual1pref, qp1, QSuffix)
		elseif qp1a and qp1a ~='' and options.qual1a and options.qual1a ~= '' then
			s = s .. qoo(QPrefix, options.qp1apref, qp1a, QSuffix)
		end
		if qp2 and qp2 ~='' and options.qual2 and options.qual2 ~= '' then s = s .. qoo(QPrefix, options.qual2pref, qp2, QSuffix) end
		if qp3 and qp3 ~='' and options.qual3 and options.qual3 ~= '' then s = s .. qoo(QPrefix, options.qual3pref, qp3, QSuffix) end
		if qp4 and qp4 ~='' and options.qual4 and options.qual4 ~= '' then s = s .. qoo(QPrefix, options.qual4pref, qp4, QSuffix) end
		if qp5 and qp5 ~='' and options.qual5 and options.qual5 ~= '' then s = s .. qoo(QPrefix, options.qual5pref, qp5, QSuffix) end
		if options.justthisqual and options.justthisqual ~= '' then if onlyqualifier then s = onlyqualifier 
			else s = nil end end  -- We need only the qualifier 
		if ro and ro ~='' and options.withro and options.withro ~= '' then s = s .. qoo(QPrefix, '' , ro, QSuffix) end
		if d and d ~='' and options.withdate and options.withdate ~= '' then
			if options.withdate == 'y' then s = s .. qoo(QPrefix, 'سنة ' , d, QSuffix)
				elseif options.withdate == 'before' then s = '*' .. d ..':' .. s..'\n'
				else s = s .. qoo(QPrefix, '' , d, QSuffix)
			end
		end
		if awardqual and options.awardqua and options.awardqua ~= '' then s = s .. qoo(QPrefix, '' , awardqual, QSuffix) end

		if tf and options.withintervall and options.withintervall ~= '' then
			if options.withintervall == 'gift' then s = s .. mw.text.tag('br') .. qoo(QPrefix, '' , tf, QSuffix)
				elseif options.withintervall == 'before' then s = qoo(QPrefix, '' , tf, QSuffix) .. s
				else s = s .. qoo(QPrefix, '' , tf, QSuffix)
			end
		end
		if utgivort and options.withutgivort and options.withutgivort ~= '' then
			if options.withutgivort == 'قوسين' then s = s .. ' ' .. qoo(QPrefix, '' , utgivort, QSuffix)
				else s = s .. ' ' .. utgivort
			end
		end
		if pr and pr ~= '' and options.getsimpleproperty and options.getsimpleproperty ~= '' then
			if options.getsimpleproperty == 'född' then s = s .. ' ' .. qoo(QPrefix, 'f. ' , pr, QSuffix)
				elseif options.getsimpleproperty == 'parentes' then s = s .. ' ' .. qoo(QPrefix, '' , pr, QSuffix)
				elseif options.getsimpleproperty == 'avnågon'  then s = s .. ' ' .. mw.text.tag('span', {}, ' av ' .. pr .. '')
			end
		end
					if type(ref) == 'table' or (options.noref and options.noref ~='') or (options.justthisqual and options.justthisqual ~='') 
						then --Do not look for references if the call is made from a reference
						table.insert( formattedStatements, s )
					else
						local t = formatReferences( statement, options )
						stat.ref = t
							if options.justref and options.justref ~= '' 
							then
								table.insert( formattedStatements, t )
							else 
								table.insert( formattedStatements, s .. t )
							end
					end
				end
				table.insert(statementsraw, stat)
			end
		end
	end
	local tot = mw.text.listToText( formattedStatements, options.separator, options.conjunction )
	if tot == '' then tot = nil end
	if options.raw and options.raw ~= '' then
		return statementsraw
	end
	return tot
end

function formatReferences( statement, options )
	local reference = {}
	if statement.references then
		local cite = require('Module:Wp/khw/Cite')
		for i, ref in pairs(statement.references) do
			local items, s = {}, nil
			if ref.snaks then
				if ref.snaks.P248 then
					for j, prop in pairs(ref.snaks.P248) do
						if prop.snaktype == 'value' then
							table.insert(items, 'Q' .. prop.datavalue.value['numeric-id'])
					end end
				elseif ref.snaks.P143 then
					for j, prop in pairs(ref.snaks.P143) do
						if prop.snaktype == 'value' then
						table.insert(items, 'Q' .. prop.datavalue.value['numeric-id'])
					end end
				end
				s =  cite.citeitem( items , ref.snaks , ref.hash , options )
			end
			table.insert(reference, s)
		end
end
	local final = table.concat(reference)
		if final and final ~= '' then
			final = final .. i18n.cateref
		end
	return final
end

function formatqualifiers( statement,s, options )
	function qua(p,enbarten,modifytime)
		if p and p ~='' then return (formatStatements({property =p,enlabelcate = 't', enbarten = (enbarten or '')
			,modifytime = (modifytime or 'longdate'), noref = 'true'}, statement.qualifiers) or '') end
	end
	if options.template and options.template ~= '' then
			s.QQ1 = qua(options.Q1)
			s.QQ2 = qua(options.Q2)
			s.QQ3 = qua(options.Q3)
			s.QQ4 = qua(options.Q4)
			s.QQ5 = qua(options.Q5)
			s.QQ6 = qua(options.Q6)
			s.QQ7 = qua(options.Q7)
			s.QQ8 = qua(options.Q8)
			s.QQ9 = qua(options.Q10)
			s.QQ10 = qua(options.Q10)
	end
	if statement.qualifiers.P1350 or statement.qualifiers.P1351 then
		s.amatch = qua("P1350",'true')
		s.goal = qua("P1351",'true')
	end
	if statement.qualifiers.P580 or statement.qualifiers.P582 or statement.qualifiers.P1365 or statement.qualifiers.P1366 then
		s.start1 = qua("P580",'true')
		s.finish1 = qua("P582",'true')
		s.before1 = qua("P1365",'true')
		s.after1 = qua("P1366",'true')
		s.constituency1 = qua("P768")
		s.series1 = qua("P1545")
		s.electedin1 = qua("P2715",'')
		s.pp1001 = qua("P1001")
		s.pp108 = qua("P108")
		s.pp642 = qua("P642")
	end
	if statement.qualifiers.P585 then
		s.datum = qua("P585",'true',options.modifyqualifiertime)
	end
    local qwe = options.qwer
	if statement.qualifiers.qwe  then
		s.ro = qua(qwe,'true')
	end
	if statement.qualifiers.P574 then
		s.dateoftaxpub = qua("P574",'true',options.modifyqualifiertime)
	end
	if statement.qualifiers.P405 then
		local author = {}
		for i, j in pairs(statement.qualifiers.P405) do
			if j.snaktype == 'value' then
				local item = 'Q' .. j.datavalue.value['numeric-id']
				local authorname = formatStatements({property = "P428", entityId = item, noref = 'true', enbarten = 'true'})
				if author and authorname ~= '' then
					table.insert(author, formatEntityId(item, {label = authorname }).value)
				else
					table.insert(author, formatEntityId(item, {}).value)
				end
			end
		end
		s.auktor = mw.text.listToText(author, ', ', ' & ')
	end	
	if statement.qualifiers.P580 or statement.qualifiers.P582 then
		local f = qua("P580",'true',options.modifyqualifiertime)
		local t =  qua("P582",'true',options.modifyqualifiertime)
				s.tifr = f .. '–' .. t
	end
	if statement.qualifiers.P585 or statement.qualifiers.P1346 then
		local fo = qua("P585",'true',options.modifyqualifiertime)
		local to = qua('P1346','true')
		s.foto = fo .. ' ' .. mw.text.tag('span', {}, ' ' .. to  .. '')
	end

	function quaaal(opti,options)
		if opti and opti ~=''  and statement.qualifiers[opti] then
			return (formatStatements({property = opti, noref = 'true', separator = options.qualifierseparator
				, conjunction = options.qualifierconjunction,size =options.size,image =options.image
				, modifytime = options.modifyqualifiertime,enlabelcate = 't',langpref = options.langpref,showlang = options.showlang}
				, statement.qualifiers) or '')
		end
	end
	if statement.qualifiers.P291 then       -- خاصية بلد النشر
		s.utgivort = quaaal('P291',options)
	end
	if statement.qualifiers.P2096 then
		s.bildtext = formatStatements({property = "P2096", noref = 'true', langpref = (options.langpref or 'khw')}, statement.qualifiers)
	end
	if options.justthisqual and options.justthisqual ~= '' and statement.qualifiers[options.justthisqual] then
		s.onlyqualifier =  quaaal(options.justthisqual,options)
	end
	if options.qual1 and options.qual1 ~= ''  and statement.qualifiers[options.qual1] then 	s.qp1 = quaaal(options.qual1,options) end
	if options.qual1a and options.qual1a ~= ''  and statement.qualifiers[options.qual1a] then s.qp1a = quaaal(options.qual1a,options) end
	if options.qual2 and options.qual2 ~= ''  and statement.qualifiers[options.qual2] then 	s.qp2 = quaaal(options.qual2,options) end
	if options.qual3 and options.qual3 ~= ''  and statement.qualifiers[options.qual3] then 	s.qp3 = quaaal(options.qual3,options) end
	if options.qual4 and options.qual4 ~= ''  and statement.qualifiers[options.qual4] then 	s.qp4 =  quaaal(options.qual4,options) end
	if options.qual5 and options.qual5 ~= ''  and statement.qualifiers[options.qual5] then 	s.qp5 = quaaal(options.qual5,options) end	
end

function formatStatement( statement, options )
    if options['claim-module'] or options['claim-function'] then
		if not options['claim-module'] or not options['claim-function'] then
            return {value = formatError( 'unknown-claim-module' )}
        end
        local formatter = require ('Module:' .. options['claim-module'])
        if not formatter then
            return {value = formatError( 'claim-module-not-found' )}
        end
        local fun = formatter[options['claim-function']]
        if not fun then
            return {value = formatError( 'claim-function-not-found' )}
        end
        return {value = fun( statement, options )}
    
    elseif statement.type == 'statement' then
    	local s = formatSnak( statement.mainsnak, options ) 
		if s and s ~= ''  then
			if statement.references then
				if options.reff and options.reff ~= ''  then
					s.reff  = formatReferences( statement, options )
				end 
			end
			if statement.qualifiers then
				qualu = formatqualifiers( statement,s, options )
				if qualu and qualu ~= '' then table.insert(qualu) end
			end
		end
		return s
	elseif not statement.type then
		return formatSnak( statement, options )
    end
	return {value = formatError( 'unknown-claim-type' )}
end
 
function formatSnak( snak, options )
    if snak.snaktype == 'somevalue' then
    	if options.somevalue then
    		if options.somevalue == '' then
    			return nil
    		else
    			return {value = options.somevalue}
    		end
    	end
        return {value =  i18n['somevalue']}
    elseif snak.snaktype == 'novalue' then
    	if options.novalue then
    		if options.novalue == '' then
    			return nil
    		else
    			return {value = options.novalue}
    		end
    	end
        return {value = i18n['novalue']}
    elseif snak.snaktype == 'value' then
    	local s = formatDatavalue( snak.datavalue, options, snak.datatype )
    	if s and options.prefix and options.prefix ~= '' then
    		s.value = options.prefix .. s.value
    	end
    	if s and options.suffix and options.suffix ~= '' then
    		s.value = s.value .. options.suffix
    	end
        if s and s.item and options.getsimpleproperty and options.getsimpleproperty ~= '' and options.getproperty and options.getproperty ~= '' then
        	local pr = formatStatements({property = options.getproperty, entityId = s.item, enbarten = options.getenbarten, noref = 'true', modifytime = options.getmodifytime, raw = options.getraw})
        	if pr then s.pr = pr end
        end
        return s
    else
        return {value = formatError( 'unknown-snak-type' )}
    end
end

 --[[ 
          datatype  wikibase-item  
 ]]

function formatwikibaseitem( datavalue, options, datatype )
        if options.formatting and options.formatting  ~= '' 
		then
			if options.formatting == 'raw' then 
				return {value = getEntityIdFromValue( datavalue.value )}
			elseif options.formatting == 'fu' then 
				return {value = mw.getCurrentFrame():expandTemplate{ title = "Cycling race/stageclassification1"
				, args = {getEntityIdFromValue( datavalue.value )}} }
			elseif options.formatting == 'sitelink' then -- for Wikidata property giving Wikimedia list
				return {value = formatsitelink(datavalue.value.id , options ) }
			else
				return {value = formatFromPattern( versalisering(datavalue.value, options), options )}
			end
		elseif options.property1 and options.property1 ~= '' then
				for i, statement in pairs( datavalue ) do
     		local entit = getEntityIdFromValue( datavalue.value )
        		local caca = formatStatements( {property =options.property1, entityId = entit, noref =options.noref ,rank=options.rank,pattern =options.property1pattern,formatting=options.property1formatting,size =options.size,image =options.image,noref='true',enbarten ='true' })
                local cooooca = (options.property1pref or '') ..''.. caca ..''.. (options.property1suff or '')
        		local asdf = formatEntityId( entit , options ).value
        			if asdf and asdf  ~= '' then
						if caca and caca  ~= '' then 
							if options.property1after then
								return {value = asdf .. cooooca } 
							else
								return {value = cooooca .. ' '.. asdf } 
							end
						else
							return {value = asdf  }
						end
					end
       end 
		elseif options.propertyimage and options.propertyimage ~= '' then
				for i, statement in pairs( datavalue ) do

        		local entit = getEntityIdFromValue( datavalue.value )
        		local caca = formatStatements( {property =options.propertyimage , entityId = entit, noref =options.noref ,rank=options.rank,pattern =options.pattern,formatting =options.propertyimageformatting ,size =options.size,image =options.image,noref='true',enbarten ='true' })
        		local asdf = formatEntityId( entit , options ).value

        		if caca and caca  ~= '' then return {value =  caca } else 
				end
       end 
	   	elseif options.property2 and options.property2 ~= '' then
				for i, statement in pairs( datavalue ) do

        		local entit = getEntityIdFromValue( datavalue.value )

        		local caca = formatStatements( {property =options.property2, entityId = entit, noref =options.noref ,rank=options.rank,pattern =options.property2pattern,size =options.size,image =options.image,propertyimage =options.property3,enbarten ='true' })
        		local asdf = formatEntityId( entit , options ).value
        			if asdf and asdf  ~= '' then
        		if caca and caca  ~= '' then return {value =  caca .. ' '.. asdf  } else return {value = asdf  } end
				end
       end else
			return {value = formatEntityId( getEntityIdFromValue( datavalue.value ), options ).value}    	
        end 
end
 --[[ 
          datatype  wikibase-property  
 ]]
function formatwikibaseproperty( datavalue, options, datatype )
	if options.formatting and options.formatting  ~= '' 
		then
			if options.formatting == 'raw' then 
				tid = getEntityIdFromValue( datavalue.value )
				else
			end
		else 
		tid =  formatEntityId( getEntityIdFromValue( datavalue.value ), options ).value
	end
	return {value = tid}
end
function formatcommonsMedia( datavalue, options, datatype )
      if options.image and options.image ~= '' then -- return real image
			tid = '[[file:' .. datavalue.value  .. '|'.. (options.size or '60')..'px|'..'border'..']]' 
        else
			tid =  versalisering(datavalue.value, options)
        end
	return {value = tid}
end
 --[[ 
          datatype math
 ]]
function formatmath( datavalue, options, datatype )
		 --return	{value = mw.text.tag('math', {}, ''.. datavalue.value..'') } -- that doesn't work well
		 return	{value =mw.getCurrentFrame():callParserFunction( '#tag:math', ''.. datavalue.value..'' ) }
end
 --[[ 
        datatype  string  -  external-id
 ]]
 
function formatstring( datavalue, options, datatype )
        if options.pattern and options.pattern ~= '' then
        		local patter = formatStatements( {property = "P1630", entityId = options.property, enbarten = 'true', noref = 'true' }) -- get formatter URL
        		local ppp = formatFromPattern( datavalue.value, {pattern = patter} )
        		local plabel = mw.wikibase.label( options.property ) or ppp 
        	if options.pattern == "auktoritetsdata" or options.pattern == "autourl" then -- like http://example.com/$1.html
        		 tid =  ppp
        	elseif options.pattern == "auktoritetsdata2" or options.pattern == "autourl2" then  -- like [http://example.com/$1.html $1]
        		 tid =  '[' .. ppp .. ' ' .. datavalue.value .. ']' 
        	elseif options.pattern == "auktoritetsdata3" or options.pattern == "autourl3"  then  -- like [http://example.com/$1.html http://example.com/$1.html]
        		 tid =  '[' .. ppp .. ' ' .. ppp .. ']' 
        	elseif options.pattern == "autourl4"  then
        		 tid =  '[' .. ppp .. ' ' .. plabel .. ']' 
        	else
            	 tid =  formatFromPattern( versalisering(datavalue.value, options), options )
            end
        else
             tid =  versalisering(datavalue.value, options)
        end
	return {value = tid}	
end
 --[[ 
        datatype  time
 ]]
function formattime( datavalue, options, datatype )
        local ModuleTime = require 'Module:wikidata2/time'
        local timen = datavalue.value 
        local modifytime = (options.modifytime or '')
        local tid = ModuleTime.getdate( timen , options)
       -- local tid =  mw.getCurrentFrame():preprocess(mall)
        if options.modifytime and options.modifytime ~= '' then
			if options.modifytime == 'q' then
				local mall = datavalue.value.time
				tid = mw.getCurrentFrame():preprocess(mall)
			elseif options.modifytime == 'precision' then
				local mall = datavalue.value.precision
				tid = mw.getCurrentFrame():preprocess(mall)
			end
		end
	return {value = tid}	
end
--[[ 
        datatype  globe-coordinate
 ]] 
function formatcoordinate( datavalue, options, datatype )
        --local GlobeCoordinate = require 'Module:Wp/khw/GlobeCoordinate'
        --return {value = GlobeCoordinate.newFromWikidataValue( datavalue.value ):toHtml()}
		local coord = datavalue.value
		local globe = datavalue.value.globe
		globe2 =  require('Module:Wp/khw/Wikidata2/Globes')[globe]
	if options.formatting  and options.formatting  ~= '' then
		if options.formatting == 'latitude' then pro =coord.latitude 
			elseif options.formatting == 'longitude' then pro =coord.longitude 
			elseif options.formatting == 'dimension' then pro =coord.dimension  
			elseif options.formatting == 'precision' then pro =coord.precision 
			elseif options.formatting == 'globe' then pro =globe 
			--elseif options.formatting == 'coord' then
				--return {value = }
		else
		end
		else
			pro =
				mw.getCurrentFrame():preprocess('{{ {{{|safesubst:}}}#invoke:Coordinates|coord'
				.. '|'.. coord.latitude
				.. '|'.. coord.longitude
				.. '|display=inline'
				.. '|globe:'.. globe2 ..'_type:landmark'
				.. '|format='..(options.formatcoord or '')..'}}'
				)..catewikidatainfo(options) 
	end
	return {value = pro }
end
 --[[ 
        datatype quantity
 ]] 
function formatquantity( datavalue, options, datatype )
		local amount, unit, cat = datavalue.value.amount, datavalue.value.unit, nil
		if unit then
			unit = unit:match('Q%d+')
		end
		local formatera = require('Module:Wp/khw/Math')
		local number = formatera.newFromWikidataValue(datavalue.value)

		local unitraw = unit
		if unit then
			-- يتحقق اذا كان هناك اي اختصار لوحدة القياس
			local lab = options.label 
			or formatStatements({property = 'P498', entityId = unit, enbarten = 'true', noref = 'true'}) 
			or formatStatements({property = 'P558', entityId = unit, enbarten = 'true', langpref = options.langpref, noref = 'true'})
			if lab and ( not options.nounitshort or options.nounitshort == '' )  then
				local s = formatEntityId( unit, {label = lab ,enlabelcate ='t' , nolink = (options.nounitlink or options.nolink) })
				unit = s.value
				cat = s.cat
			else -- om det inte finns en förkortning
				local s = formatEntityId( unit, {nolink = options.nounitlink ,enlabelcate ='t'})
				unit = s.value
				cat = s.cat
			end
		end
		return {value = number .. ' ' .. (unit or ''), amount = amount, unit = unit, unitraw = unitraw, cat = cat}
end

 --[[ 
       datatype  url
 ]]  
function formaturl( datavalue, options, datatype )
		if options.label and options.label ~= '' then
		pro = '[' .. datavalue.value .. ' ' .. options.label .. ']' 
		else
			pro = datavalue.value 
		end
	return {value = pro }
end

 --[[ 
       datatype   monolingualtext
 ]] 
function formatmonolingualtext( datavalue, options, datatype )
		language = mw.language.fetchLanguageName(datavalue.value.language, 'khw')
		if options.langpref and options.langpref ~= '' then
			langpref = options.langpref
			if datavalue.value.language == langpref
				then
					valu  = mw.text.tag('span', {title = language}, datavalue.value.text)
					lange = '('.. language..')'
					if options.showlang and options.showlang ~= '' then 
						return {value =valu  ..' '..lange}
					else 
						return {value =valu}
					end
			end
		else 
			lange = '('.. language..')'
			valu = mw.text.tag('span', {title = language}, datavalue.value.text)
			if options.showlang and options.showlang ~= '' then
				return {value =valu  ..' '..lange}
			else
				return {value =valu}
			end
		end
end

function formatDatavalue( datavalue, options, datatype )
    --Use the customize handler if provided
    if options['value-module'] or options['value-function'] then
        if not options['value-module'] or not options['value-function'] then
            return {value = formatError( 'unknown-value-module' )}
        end
        local formatter = require ('Module:' .. options['value-module'])
        if not formatter then
            return {value = formatError( 'value-module-not-found' )}
        end
        local fun = formatter[options['value-function']]
        if not fun then
            return {value = formatError( 'value-function-not-found' )}
        end
        return {value = fun( datavalue, datatype, options)}
    end
    --Default formatters
 		if datatype == 'wikibase-item' then return   formatwikibaseitem( datavalue, options, datatype ) 
 	elseif datatype == 'wikibase-property' then return   formatwikibaseproperty( datavalue, options, datatype ) 
 	elseif datatype == 'commonsMedia' then return   formatcommonsMedia( datavalue, options, datatype )
 	elseif datatype == 'math' then return       formatmath( datavalue, options, datatype )
 	elseif datatype == 'time' then return formattime( datavalue, options, datatype )
 	elseif datatype == 'string' or datatype == 'external-id' then return  formatstring( datavalue, options, datatype )
 	elseif datatype == 'globe-coordinate' then return  formatcoordinate( datavalue, options, datatype )
 	elseif datatype == 'quantity' then return   formatquantity( datavalue, options, datatype )
 	elseif datatype == 'url' then return   formaturl( datavalue, options, datatype )
 	elseif datatype == 'monolingualtext' then return  formatmonolingualtext( datavalue, options, datatype )
    else
        return {value = formatError( 'unknown-datatype' )}
    end
end

function formatEntityId( entityId, options )
	local label = options.label or mw.wikibase.label( entityId )
	if label == '' then
		label = mw.wikibase.label( entityId ) or nil
	end
    local link = mw.wikibase.sitelink( entityId )
    if link and (not options.nolink or options.nolink == '') then
        if label and label ~= '' then
            return {value = '[[:' .. link .. '|' .. versalisering(label, options) .. ']]'.. catewikidatainfo(options), label = label }
        else
            return {value = '[[:' .. versalisering(link, options) .. ']]'.. catewikidatainfo(options), label = link }
        end
    else
    	if label and label ~= '' 
    		then
    		local label3 = Labelfunction( entityId, label,options.label, options)
    		return {value = label3 , label = label}
    	else return ''

    	end
    	return '' --{value = entityId, cat = 'som har labels med Qid', label = entityId}
    end
end
 --[[ 
       function to get any link from any sister project
 ]] 
function sitelink( id , wikisite )
	local site = wikisite or 'arwiki'
	local entity = mw.wikibase.getEntityObject(id)
		if entity
		and entity.sitelinks 
		and entity.sitelinks[''..site..'']
		and entity.sitelinks[''..site..''].site 
		and entity.sitelinks[''..site..''].title 
		then
			if entity.sitelinks[''..site..''].site == site then
			return entity.sitelinks[''..site..''].title
			else return ''
			end
		end
end
 --[[ 
       function to get only the value with link
 ]] 
function formatsitelink( entityId, options )
    local link = sitelink( entityId )
    if link and link ~= ''  then
		if not options.nolink or options.nolink == '' then
            return '[[' .. versalisering(link, options) .. ']]'.. catewikidatainfo(options)
    else
    		return versalisering(link, options)
		end
    else 
		return ''
    	end

end
 --[[ 
       function to replace $1 with string
 ]] 
function formatFromPattern( str, options )
    return mw.ustring.gsub( options.pattern, '$1', str ) .. '' --الحصول على اول نتيجة للدالة
end
 
function addTrackingCategory(prop,options)
	local cat =  require('Module:Wp/khw/Wikidata/تتبع').makecategory1
	local category =  cat(options)
	if category and category ~= '' then
		return prop .. '  ' .. category
	else 
		return prop
	end
end

-- Function to check whether a certain item is a parent of a given item.
-- If pExitItem is reached without finding the searched parent item, the search stops.
-- A parent is connected via P31 or P279.
-- Attention: very intensive function, use carefully!
function isParent(property, pItem, pParent, pExitItem, pMaxDepth, pDepth)
	if not pDepth then pDepth = 0 end
	local entity = mw.wikibase.getEntity(pItem)
	if not entity then return false end
	local claims31
	local claims279
	if entity.claims then 
		if property and property ~= '' then
			claims31 = entity.claims[mw.wikibase.resolvePropertyId(property)] 
		else
			claims31 = entity.claims[mw.wikibase.resolvePropertyId('P31')] 
			claims279 = entity.claims[mw.wikibase.resolvePropertyId('P279')] 
		end
	else
		return false
	end
		function getSnakValue(snak)
		if snak.snaktype == "value" then
			if snak.datavalue.type == "wikibase-entityid" then 
				data = snak.datavalue.value['numeric-id']
				return data
			end
		end
		end
	if not claims31 and not claims279 then return false end
	local parentIds = {}
		if claims31 and #claims31 > 0 then
			for i, v in ipairs(claims31) do parentIds[#parentIds+1] = getSnakValue(v.mainsnak) end
		end
		if claims279 and #claims279 > 0 then
			for i, v in ipairs(claims279) do parentIds[#parentIds+1] = getSnakValue(v.mainsnak) end
		end
	-- check if searched parent or exit item is reached or do recursive call
	if not parentIds[1] or #parentIds == 0 then return false end
	local itemString = ""
	local result = nil
	for i, v in ipairs(parentIds) do
		if not v then return false end
		itemString = "Q" .. v
		if itemString == pParent then 
			-- successful!
			return true
		elseif itemString == pExitItem then --or itemString == "Q35120"  
			-- exit if either "exit item" or node item (Q35120) is reached
			return false
		else
			if pDepth+1 < pMaxDepth then
				result = isParent(property, itemString, pParent, pExitItem, pMaxDepth, pDepth+1)
			else return false end
			
			if result == true then return result end
		end
	end
	do return false end
end

local p = {}
 
function p.formatEntityId( entityId, options )
	return formatEntityId( entityId, (options or {}) )
end
 --[[ 
       function to add tracking category
 ]] 

 --[[ 
       The main function 
 ]] 
function p.formatStatements( frame, key )
    local args = frame.args
    --If a value if already set, use it
    if args.value and args.value ~= '' then
        return args.value
    end
    local prop = formatStatements( frame.args, key )
	if prop and prop ~= '' then
    	if args.mainprefix and args.mainprefix ~= '' then -- mainprefix
    		prop = args.mainprefix .. prop
    	end
    	if args.mainsuffix and args.mainsuffix ~= '' then  -- mainsuffix
    		prop = prop .. args.mainsuffix
    	end
		if args.addTrackingCat and args.addTrackingCat ~= '' then   -- add tracking cat
		prop =  addTrackingCategory(prop,frame.args)
		end
		if args.mainsuffixAfterIcon and args.mainsuffixAfterIcon ~= '' then   -- another suffix but after wikidata icon
		prop =  prop .. args.mainsuffixAfterIcon 
		end
	else 
    	if args.NoPropValue and args.NoPropValue ~= '' then -- value if no local value and no wikidata value  
    		prop = args.NoPropValue
    	end
	end
    return prop
end

function p.formatStatementsFromLua( options, key ) --  main function but to use from lua module
    --If a value if already set, use it
    if options.value and options.value ~= '' then
        return options.value
    end
    local s = formatStatements( options, key )
    if s == '' then
    	s = nil
    end
	if options.addTrackingCat and options.addTrackingCat ~= '' then   -- add tracking cat
		s=  addTrackingCategory(s,options)
	end
    return s
end


function p.isSubclass(frame)
	if not frame.args["parent"] then return false end
	
	local maxDepth
	maxDepth = frame.args["maxDepth"] or 10
	if not type(maxDepth) == "number" then maxDepth = 5 end
	property = frame.args["property"]
	local result
	result = isParent(property, frame.args["id"], frame.args["parent"], frame.args["exitItem"], maxDepth)
	if frame.args["returnInt"] then
		if result == true then return 1 else return nil end
	else
		return result
	end
end

-- Return the site link for a given data item and a given site (the current site by default) 
function p.getSiteLink( frame )
	local site = frame.args[2] or frame.args.site
	local id = frame.args[1]  or frame.args.id
	    local link = sitelink( id , site )
    if link and link ~= ''  then
            return link
	end
end

function p.getSiteLink1(frame)
	local project = frame.args[1] 
	local id = frame.args[2]
	local link =sitelink( id , project )
	var = link
	return var
end

-- returns the page id (Q...) of the current page or nothing of 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.descriptionIn(frame)
	local langcode = frame.args[1]
	local id = frame.args[2] -- "id" must be nil, as access to other Wikidata objects is disabled in Mediawiki configuration

	return descriptionIn( langcode ,id  )
end
function p.labelIn(frame)
	local langcode = frame.args[1]
	local id = frame.args[2] -- "id" must be nil, as access to other Wikidata objects is disabled in Mediawiki configuration

	return labelIn( langcode ,id  )
end
function p.ViewSomething(frame)   -- from en:Wp/khw/Module:Wikidata
	local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
          if f.args.id and f.args.id ~='' then aa = f.args.id end
	local data = mw.wikibase.getEntityObject(aa)
	if not data then
		return nil
	end
	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			if type(data) == "table" then
				return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY)
			else
				return tostring(data)
			end
		end
		data = data[index] or data[tonumber(index)]
		if not data then
			return
		end
		i = i + 1
	end
end
function p.Dump(frame)
	local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
          if f.args.id and f.args.id ~='' then aa = f.args.id end
	local data = mw.wikibase.getEntityObject(aa)
	if not data then
		return i18n.warnDump
	end
	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return frame:extensionTag("source", mw.dumpObject(data),{ lang= 'lua'}).. i18n.warnDump
		end
		data = data[index] or data[tonumber(index)]
		if not data then
			return i18n.warnDump
		end
		i = i + 1
	end
end

return p