Module:Wikidata2
local fallback = {'en', 'nb', 'da', 'nn', 'de', 'fr', 'es', 'it', 'pt'}
 local formatera = require('Module:Math')
 local i18n = {
     [&quot;errors&quot;] = {
         [&quot;property-param-not-provided&quot;] = &quot;Property parameter not provided.&quot;,
         [&quot;entity-not-found&quot;] = &quot;Entity not found.&quot;,
         [&quot;unknown-claim-type&quot;] = &quot;Unknown claim type.&quot;,
         [&quot;unknown-snak-type&quot;] = &quot;Unknown snak type.&quot;,
         [&quot;unknown-datatype&quot;] = &quot;Unknown datatype.&quot;,
         [&quot;unknown-entity-type&quot;] = &quot;Unknown entity type.&quot;,
         [&quot;unknown-value-module&quot;] = &quot;You must set both value-module and value-function parameters.&quot;,
         [&quot;value-module-not-found&quot;] = &quot;The module pointed by value-module not found.&quot;,
         [&quot;value-function-not-found&quot;] = &quot;The function pointed by value-function not found.&quot;
     },
     [&quot;somevalue&quot;] = &quot;''unknown value''&quot;,
     [&quot;novalue&quot;] = &quot;''no value''&quot;
 }
 local sortingproperties = {'P585','P571','P580','P569','P582','P570'}
 
 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(&quot;{{lcfirst: &quot; .. label .. &quot; }}&quot;)
 	elseif versalisering == 'ucfirst' then
 		return mw.language.getContentLanguage():ucfirst( label )
 	elseif versalisering == 'lc' then
 		return mw.getCurrentFrame():preprocess(&quot;{{lc: &quot; .. label .. &quot; }}&quot;)
 	elseif versalisering == 'uc' then
 		return mw.getCurrentFrame():preprocess(&quot;{{uc: &quot; .. label .. &quot; }}&quot;)
 	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 = 'ja', sortbytime = 'chronological', noref = 'ja'})
 	end
 end
 
 function comparedates(a, b) 
 	if a and b then
 		return a &gt; 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 getLabelFromFallBack( id ) 
 	local entity = getEntityFromId( id )
  	for k, v in pairs(fallback) do
 		if entity.labels[v] then
 			return {value = entity.labels[v].value, language = entity.labels[v].language}
 		end
 	end
 	-- Om inget fallback-språk finns av de i variabeln ovan, så används det först definierade i objektet
 	if entity.labels then 
 		for v, k in pairs(entity.labels) do
 			return {value = k.value, language = k.language}
 		end
 	end
 	return {value = '-', language = ''}
 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 '&lt;span class=&quot;error&quot;&gt;' .. i18n.errors[key] .. '&lt;/span&gt;'
 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 ) == &quot;table&quot; then
         	entity = options.entity
     	else
         	entity = getEntityFromId( options.entityId )
     	end
  
     	if not entity then
         	return '' --TODO error?
     	end
  
     	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
 			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 &quot;språk = svenska&quot;, ta bara med dessa
 		--alternativt om det finns statements som har en qualifier som säger &quot;skriptsystem == latinska alfabetet&quot;
 		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'] == 9027 then -- Q9027 = 'svenska'
 							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'] == 8229 then -- Q8229 = 'latinska alfabetet'
 							table.insert( claims2, statement )
 						end
 					end
 				end
 			end
 			if #claims2 &gt; 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 &gt; 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 )
 			local s = stat.value
 			local d = stat.datum
 			local tf = stat.tifr
 			local pr = stat.pr
 			if s == '' then s = nil end
 			if s then
 				if d and options.withdate and options.withdate ~= '' then
 					s = s .. mw.text.tag('small', {}, ' (' .. d .. ')')
 				end
 				if tf and options.withintervall and options.withintervall ~= '' then
 					if options.withintervall == 'gift' then
 						s = s .. mw.text.tag('br') .. mw.text.tag('small', {}, '(g. ' .. tf .. ')')
 					else
 						s = s .. mw.text.tag('small', {}, ' (' .. tf .. ')')
 					end
 				end
 				
 				if options.getsimpleproperty == 'född' and pr and pr ~= '' then
 					s = s .. ' ' .. mw.text.tag('small', {}, '(f. ' .. pr .. ')')
 				end
 				if type(ref) == 'table' or (options.noref and options.noref ~='') then --Inte leta efter referenser om själva anropet görs från en referens
 					table.insert( formattedStatements, s )
 				else
 					local t = formatReferences( statement, options )
 					stat.ref = t
 					table.insert( formattedStatements, s .. t )	
 				end
 			end
 			table.insert(statementsraw, stat)
 		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('Modul: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
 						table.insert(items, 'Q' .. prop.datavalue.value['numeric-id'])
 					end
 				end
 				s = cite.citeitem( items, ref.snaks, options ) 
 				if s == '' or not s then
 					s = 'Källangivelsen på Wikidata använder propertys som inte känns igen av Modul:Cite'
 				end
 			end
 			table.insert(reference, mw.getCurrentFrame():extensionTag( 'ref', s, {name = ref.hash} ) )
 		end
 	end
 	return table.concat(reference)
 end
 function formatStatement( statement, options )
     if statement.type == 'statement' then
     	local s = formatSnak( statement.mainsnak, options )
     	if statement.qualifiers then
     		if statement.qualifiers.P585 then
     			s.datum = formatStatements({property = &quot;P585&quot;, enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers)
 			end
 			if statement.qualifiers.P574 then
 				s.dateoftaxpub = formatStatements({property = &quot;P574&quot;, enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers)
 			end
 			if statement.qualifiers.P405 then
 				local auktorer = {}
 				for i, j in pairs(statement.qualifiers.P405) do
 					if j.snaktype == 'value' then
 						local item = 'Q' .. j.datavalue.value['numeric-id']
 						local auktorsnamn = formatStatements({property = &quot;P428&quot;, entityId = item, noref = 'ja', enbarten = 'ja'})
 						if auktorsnamn and auktorsnamn ~= '' then
 							table.insert(auktorer, formatEntityId(item, {label = auktorsnamn}).value)
 						else
 							table.insert(auktorer, formatEntityId(item, {}).value)
 						end
 					end
 				end
 				s.auktor = mw.text.listToText(auktorer, ', ', ' &amp; ')
 			end			
 			if statement.qualifiers.P580 or statement.qualifiers.P582 then
 				local f = formatStatements({property = &quot;P580&quot;, enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers) or ''
 				local t = formatStatements({property = &quot;P582&quot;, enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers) or ''
 				s.tifr = f .. '–' .. t
 			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.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 = 'ja', 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
  
 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.value, options )}
     end
  
     --Default formatters
     if datatype == 'wikibase-item' then
     	local s = formatEntityId( getEntityIdFromValue( datavalue.value ), options )
     	s.item = getEntityIdFromValue( datavalue.value )
         return s
         
     elseif datatype == 'string' or datatype == 'commonsMedia' then
         if options.pattern and options.pattern ~= '' then
         	if options.pattern == &quot;auktoritetsdata&quot; then
         		local patter = formatStatements( {property = &quot;P1630&quot;, entityId = options.property, enbarten = 'true', noref = 'true' })
         		return {value = formatFromPattern( datavalue.value, {pattern = patter} )}
         	elseif options.pattern == &quot;auktoritetsdata2&quot; then
         		local patter = formatStatements( {property = &quot;P1630&quot;, entityId = options.property, enbarten = 'true', noref = 'true' })
         		return {value = '[' .. formatFromPattern( datavalue.value, {pattern = patter} ) .. ' ' .. datavalue.value .. ']' } 
         	else
             	return {value = formatFromPattern( versalisering(datavalue.value, options), options )}
             end
         else
             return {value = versalisering(datavalue.value, options), label = datavalue.value}
         end
         
     elseif datatype == 'time' then
         local Time = require 'Module:Time'
         local tid = Time.newFromWikidataValue( datavalue.value ):toHtml()
         if options.modifytime == 'longdate' then
         	local mall = ''
         	if datavalue.value.precision &gt;= 11 then
         		mall = '{{#time:j F Y|' .. string.gsub(datavalue.value.time,'-00','-01') .. '}}'
 				tid = mw.getCurrentFrame():preprocess(mall)
         	elseif datavalue.value.precision == 10 then
         		mall = '{{#time:F Y|' .. string.gsub(datavalue.value.time,'-00','-01') .. '}}'
         		tid = mw.getCurrentFrame():preprocess(mall)
         	elseif datavalue.value.precision == 9 then
         		mall = '{{#time:Y|' .. string.gsub(datavalue.value.time,'-00','-01') .. '}}'
         		tid = mw.getCurrentFrame():preprocess(mall)
         	end
     	elseif options.modifytime == 'Y' then
     		local mall = '{{#time:Y|' .. string.gsub(datavalue.value.time,'-00','-01') .. '}}'
     		tid = mw.getCurrentFrame():preprocess(mall)
         end
         return {value = tid}
         
     elseif datatype == 'globecoordinate' then
         local GlobeCoordinate = require 'Module:GlobeCoordinate'
         return {value = GlobeCoordinate.newFromWikidataValue( datavalue.value ):toHtml()}
     
 	elseif datatype == 'quantity' then 
 		local amount, unit, cat = datavalue.value.amount, datavalue.value.unit, nil
 		if unit then
 			unit = unit:match('Q%d+')
 		end
 		
 		local number = formatera.newFromWikidataValue(datavalue.value)
 
 		local unitraw = unit
 		if unit then
 			-- Kontrollerar om det finns någon förkortning för denna 'unit'
 			local lab = options.label 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, 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})
 				unit = s.value
 				cat = s.cat
 			end
 		end
 		return {value = number .. ' ' .. (unit or ''), amount = amount, unit = unit, unitraw = unitraw, cat = cat}
 		
 	elseif datatype == 'url' then
 		if options.label and options.label ~= '' then
 			return {value = '[' .. datavalue.value .. ' ' .. options.label .. ']'}
 		else
 			return {value = datavalue.value}
 		end
 		
 	elseif datavalue.type == 'monolingualtext' then
 		return {value = mw.text.tag('span', {title = mw.language.fetchLanguageName(datavalue.value.language, 'sv')}, datavalue.value.text)}
 		
     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) .. ']]', label = label }
         else
             return {value = '[[:' .. versalisering(link, options) .. ']]', label = link }
         end
     else
     	if label then
     		return {value = versalisering(label, options), label = label}
     	else
     		local s = getLabelFromFallBack( entityId )
     		local l = mw.language.fetchLanguageName(s.language, 'sv')
     		if not l or l == '' then
     			l = 'okänt språk'
     		end
     		if s then
     			return {value = mw.text.tag('span', {title = l}, versalisering(s.value, options) ), cat = 'med labels på ' .. l, label = s.value }
     		end
     	end
     	return {value = entityId, cat = 'som har labels med Qid', label = entityId}
     end
 end
  
 function formatFromPattern( str, options )
     return mw.ustring.gsub( options.pattern, '$1', str ) .. '' --Hack to get only the first result of the function
 end
  
 local p = {}
  
 function p.formatEntityId( entityId, options )
 	return formatEntityId( entityId, (options or {}) )
 end
 	
 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
     return formatStatements( frame.args, key )
 end
  
 function p.formatStatementsFromLua( options, key )
     --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
     return s
 end
  
 -- Return the site link (for the current site) for a given data item.
 function p.getSiteLink( frame )
     if frame.args[1] == nil then
         entity = mw.wikibase.getEntityObject()
         if not entity then
         	entity = mw.wikibase.getEntityObject(frame.args[1])
         end
         id = entity.id
     else
         id = frame.args[1]
     end
  
     return mw.wikibase.sitelink( id )
 end
 
 -- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
 -- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
 -- uses the newer mw.wikibase calls instead of directly using the snaks
 -- formatPropertyValues returns a table with the P1323 values concatenated with &quot;, &quot; so we have to split them out into a table in order to construct the return string
 p.getTAValue = function(frame)
 	local ent = mw.wikibase.getEntityObject()
 	local props = ent:formatPropertyValues('P1323')
 	local out = {}
 	local t = {}
 	for k, v in pairs(props) do
 		if k == 'value' then
 			t = mw.text.split( v, &quot;, &quot;)
 			for k2, v2 in pairs(t) do
 				out[#out + 1] = &quot;[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/&quot; .. string.sub(v2, 2) .. &quot;%20Entity%20TA98%20EN.htm &quot; .. v2 .. &quot;]&quot;
 			end
 		end
 	end
 	ret = table.concat(out, &quot;&lt;br&gt; &quot;)
 	if #ret == 0 then
 		ret = &quot;Invalid TA&quot;
 	end
 	return ret
 end