Modul:LocationAndCountry
Aspect

Implementează formatul {{Loc, Țară}}, dar poate fi apelat prin intermediul funcției displayFromParams și din alte module pentru a afișa țara atașată de un loc la un anumit moment de timp.
-- will display a wikidata property representing a location, followed by a comma and the name of the country, both with wikilinks
-- the first argument specifies the parameter to be displayed
-- the second argument specifies the entity ID
-- the third argument specifies a timestamp showing the moment in time for which the country is to be identified
-- the fourth argument specifies the maximum number of values to be processed (default 1)
-- the fifth argument specifies the separator to use when displaying multiple values
local getArgs = require('Modul:Arguments').getArgs
local Wikidata = require('Modul:Wikidata')
local lacData = mw.loadData('Modul:LocationAndCountry/data')
local TableTools = require('Modul:TableTools')
local GregorianDate = require('Modul:GregorianDate')
local DateUtils = require('Modul:DateUtils')
local Set = require('Modul:Set')
local illWd = require('Modul:Ill-wd').fromArgs
local p = {}
local function getClaimsForParam(entity, param)
local claims = nil
local workingEntityId = nil
if type(entity) == 'table' then
workingEntityId = entity.id
claims = entity:getBestStatements(param)
else
workingEntityId = entity
if not workingEntityId then workingEntityId = mw.wikibase.getEntityIdForCurrentPage() end
if type(entity) == 'number' then workingEntityId = 'Q' .. tostring(entity) end
if workingEntityId == nil then return '' end
claims = mw.wikibase.getBestStatements(workingEntityId, param)
end
return claims, workingEntityId
end
local function getTimestamp(timestamp, workingEntityId)
local ts = nil
if timestamp then
if type(timestamp) == 'string' and mw.ustring.gmatch(timestamp, 'P%d+') then
local wdDates = Wikidata.findDateValues(timestamp, workingEntityId)
if wdDates then for _,eachWdDate in ipairs(wdDates) do
if Wikidata.isClaimTrue(eachWdDate.claim) and Wikidata.hasValueSnak(eachWdDate.claim) then
ts = GregorianDate.convertToGregorianIfInInterval(eachWdDate)
break
end
end end
end
if ts == nil and type(timestamp) == 'string' then
ts = DateUtils.parseYear(timestamp)
elseif ts == nil and type(timestamp) == 'table' and timestamp.year then
ts = timestamp
end
end
return ts
end
local function getUatsAndCountryFromQuals(claim)
if not Wikidata.isClaimTrue(claim) or not claim.qualifiers then return nil end
local country = nil
local uats = {}
if claim.qualifiers['P17'] then for _,eachCountryQual in ipairs(claim.qualifiers['P17']) do
if Wikidata.isValueSnak(eachCountryQual) then
country = eachCountryQual.datavalue.value.id
break
end
end end
if claim.qualifiers['P131'] then for _,eachUatQual in ipairs(claim.qualifiers['P131']) do
if Wikidata.isValueSnak(eachUatQual) then
table.insert(uats, eachUatQual.datavalue.value.id)
end
end end
return uats, country
end
local function getCountryIdForTimestamp(entityId, ts)
local countryClaim = Wikidata.findClaimForTimestamp(entityId, 'P17', ts)
if countryClaim and Wikidata.hasValueSnak(countryClaim) then
return countryClaim.mainsnak.datavalue.value.id
else
return Wikidata.loadOneValueInChain({entityId, 'P17', 'raw'})
end
end
-- returns 0, 1 or 2 - the number of admin units to be pulled
local function shouldPullUats(entityId)
-- villages, rural settlements, should get 2 uats
if Wikidata.isA(entityId, lacData.adminUnitExpandableLocationTypes) then
return 2
end
-- locations in federal countries should get at least one UAT regardless of size
local countryId = Wikidata.loadOneValueInChain({entityId, 'P17', 'raw'})
if countryId and Wikidata.isA(countryId, { 'Q22676603' }) then
return 1
end
-- only big cities should have just the country
if not Wikidata.isA(entityId, {'Q1549591', 'Q1637706'}) then
return 1
end
return 0
end
local function recurseUats(entityId, ts)
local crtUatId = entityId
local crtCountryId = Wikidata.loadOneValueInChain({entityId, 'P17', 'raw'})
local timestampedCountryId = getCountryIdForTimestamp(entityId, ts)
local uatList = {}
while crtUatId and crtUatId ~= crtCountryId and crtUatId ~= timestampedCountryId do
local timestampedUatClaim = Wikidata.findClaimForTimestamp(crtUatId, 'P131', ts)
crtUatId = timestampedUatClaim and Wikidata.hasValueSnak(timestampedUatClaim) and timestampedUatClaim.mainsnak.datavalue.value.id or Wikidata.loadOneValueInChain({entityId, 'P131', 'raw'})
if (TableTools.contains(uatList, crtUatId)) then
break
end
table.insert(uatList, crtUatId)
end
mw.logObject(uatList, 'uat list')
table.remove(uatList, #uatList)
return uatList
end
local function shouldSkipLocation(entityId)
return Wikidata.isA(entityId, lacData.escalatableLocationTypes)
end
local function trimUats(uatList)
while #uatList > 0 and (Wikidata.isA(uatList[1], lacData.skippableUatTypes) or TableTools.contains(lacData.skippableUats, uatList[1])) do
table.remove(uatList, 1)
end
while #uatList > 0 and (Wikidata.isA(uatList[#uatList], lacData.skippableUatTypes) or TableTools.contains(lacData.skippableUats, uatList[#uatList])) do
table.remove(uatList, #uatList)
end
return uatList
end
local function resolvePartName(partId, ts)
if TableTools.contains(lacData.invariantLocations, partId) then
return illWd(partId)
end
local crtCountryId = Wikidata.loadOneValueInChain({partId, 'P17', 'raw'})
if crtCountryId and TableTools.contains(lacData.invariantLocationCountries, crtCountryId) then
return illWd(partId)
end
if TableTools.size(Set.intersection(recurseUats(partId), lacData.invariantLocationUats)) > 0 then
return illWd(partId)
end
if Wikidata.isA(partId, lacData.invariantLocationTypes) then
return illWd(partId)
end
local countryId = getCountryIdForTimestamp(partId, ts)
if not countryId then return illWd(partId) end
local countryOfficialLangClaims = Wikidata.findBestClaimsForProperty(countryId, 'P37')
local offLangCode = nil
for _,eachOffLangClaim in ipairs(countryOfficialLangClaims) do
if Wikidata.hasValueSnak(eachOffLangClaim) and (not eachOffLangClaim.qualifiers or not eachOffLangClaim.qualifiers['P518']) then
local eachOffLangId = eachOffLangClaim.mainsnak.datavalue.value.id
local writingSystem = Wikidata.loadOneValueInChain({eachOffLangId, 'P282', 'raw'})
while writingSystem and writingSystem ~= '' and writingSystem ~= 'Q8229' do
writingSystem = Wikidata.loadOneValueInChain({writingSystem, 'P282', 'raw'})
end
if writingSystem == 'Q8229' then
offLangCode = Wikidata.loadOneValueInChain({eachOffLangId, 'P218'})
end
end
end
offLangCode = offLangCode or 'ro'
local officialNameClaim = Wikidata.findClaimForTimestamp(partId, 'P1448', ts, offLangCode)
if officialNameClaim and Wikidata.isClaimTrue(officialNameClaim) and Wikidata.hasValueSnak(officialNameClaim) then
return illWd(partId, officialNameClaim.mainsnak.datavalue.value.text)
else
return illWd(partId, Wikidata.findLabel(partId, offLangCode))
end
return illWd(partId)
end
local function resolvePartNames(partIds, ts)
if not partIds then return nil end
local res = {}
for _,partId in ipairs(partIds) do
table.insert(res, resolvePartName(partId, ts))
end
return res
end
local function displayFromParams(param, entity, timestamp, maxvalues, separator)
if param == nil then return '' end
local claims, workingEntityId = getClaimsForParam(entity, param)
local ts = getTimestamp(timestamp, workingEntityId)
local valueList = {}
local maxvalues = maxvalues or 1
if claims and 0 < #claims then
for _,actualClaim in ipairs(claims) do
local uatEntitiesIds = {}
local countryId = nil
local locationEntityId = nil
if Wikidata.isClaimTrue(actualClaim) and Wikidata.hasValueSnak(actualClaim) then
-- get admin unit(s) and/or country from qualifiers
uatEntitiesIds, countryId = getUatsAndCountryFromQuals(actualClaim)
locationEntityId = actualClaim.mainsnak.datavalue.value.id
countryId = countryId or getCountryIdForTimestamp(actualClaim.mainsnak.datavalue.value.id, ts)
-- (1) see if admin unit needs to be pulled
local uatsEnabled = shouldPullUats(actualClaim.mainsnak.datavalue.value.id)
if uatsEnabled > 0 then
-- (2) pull all admin units based on timestamp until reaching nothing, self or country
local allUats = recurseUats(actualClaim.mainsnak.datavalue.value.id, ts)
-- (3) if the location itself is to be skipped, keep the first admin unit in the list as location
while #allUats > 0 and shouldSkipLocation(locationEntityId) do
locationEntityId = table.remove(allUats, 1)
end
-- (4) apply rules to eliminate from both ends
allUats = trimUats(allUats)
-- (5) keep only first and last (or the only one if only one is left)
uatEntitiesIds = #allUats == 0 and {} or #allUats == 1 and allUats or uatsEnabled == 1 and {allUats[#allUats]} or {allUats[1], allUats[#allUats]}
else
uatEntitiesIds = {}
end
local allPartIds = {}
table.insert(allPartIds, locationEntityId)
for __,eachUat in ipairs(uatEntitiesIds) do table.insert(allPartIds, eachUat) end
local allPartLinks = resolvePartNames(allPartIds, ts)
table.insert(allPartLinks, illWd(countryId, lacData.countryNameOverrides[countryId]))
local crtVal = table.concat(allPartLinks, ', ')
table.insert(valueList, crtVal)
end
if #valueList > maxvalues then
break
end
end
end
return table.concat(valueList, separator or '; ')
end
p.displayFromParams = displayFromParams
local function displayFromArgs(args)
local param = nil
local entity = nil
local timestamp = nil
local maxvalues = 1
local separator = '; '
if args[1] or args['param'] then
param = args[1] or args['param']
end
if args[2] or args['entityId'] then
entity = args[2] or args['entityId']
end
if args[3] or args['timestamp'] then
timestamp = args[3] or args['timestamp']
end
if args[4] or args['maxvalues'] then
maxvalues = tonumber(args[4] or args['maxvalues'])
end
if args[5] or args['separator'] then
separator = args[5] or args['separator']
end
return displayFromParams(param, entity, timestamp, maxvalues, separator)
end
p.displayFromArgs = displayFromArgs
p.displayFromFrame = function(frame)
local args = getArgs(frame, { frameOnly = true })
return displayFromArgs(args)
end
p.displayFromParentFrame = function(frame)
local args = getArgs(frame, { parentOnly = true})
return displayFromArgs(args)
end
return p