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 getValueByTimestamp = require('Modul:TimestampedTable').getValueByTimestamp
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, countryId)
-- 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
if countryId and Wikidata.isA(countryId, { 'Q22676603', 'Q43702' }) 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({crtUatId, 'P131', 'raw'})
if (TableTools.contains(uatList, crtUatId)) then
break
end
table.insert(uatList, crtUatId)
end
if #uatList > 0 and uatList[#uatList] == crtCountryId or uatList[#uatList] == timestampedCountryId then
table.remove(uatList, #uatList)
end
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, crtCountryId)
if lacData.locationNameOverrides[partId] then
local timestampedLabel = getValueByTimestamp(lacData.locationNameOverrides[partId], ts)
return illWd(partId, timestampedLabel)
end
local offLangCodes = {}
mw.logObject(crtCountryId, 'country id for ' .. partId)
if TableTools.contains(lacData.invariantLocations, partId) or
(crtCountryId and TableTools.contains(lacData.invariantLocationCountries, crtCountryId))
or TableTools.size(Set.intersection(recurseUats(partId), lacData.invariantLocationUats)) > 0
or Wikidata.isA(partId, lacData.invariantLocationTypes) then
offLangCodes = { 'ro' }
else
local officialLangClaims = Wikidata.findBestClaimsForProperty(partId, 'P37')
if not officialLangClaims or #officialLangClaims == 0 then
local countryId = getCountryIdForTimestamp(partId, ts)
if not countryId then return illWd(partId) end
officialLangClaims = Wikidata.findBestClaimsForProperty(countryId, 'P37')
end
for _,eachOffLangClaim in ipairs(officialLangClaims) 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
local offLangCode = Wikidata.loadOneValueInChain({eachOffLangId, 'P218'})
if offLangCode and offLangCode ~= '' then
table.insert(offLangCodes, offLangCode)
end
end
end
end
end
if #offLangCodes == 0 then table.insert(offLangCodes, 'ro') end
for _,offLangCode in ipairs(offLangCodes) do
local wdPropForName = Wikidata.isA(partId, lacData.shortNameLocationTypes) and 'P1813' or 'P1448'
local officialNameClaim = Wikidata.findClaimForTimestamp(partId, wdPropForName, ts, offLangCode)
if officialNameClaim and Wikidata.isClaimTrue(officialNameClaim) and Wikidata.hasValueSnak(officialNameClaim) then
return illWd(partId, officialNameClaim.mainsnak.datavalue.value.text)
end
end
return illWd(partId, Wikidata.findLabel(partId, offLangCodes[1]))
end
local function resolvePartNames(partIds, ts, crtCountryId)
if not partIds then return nil end
local res = {}
for _,partId in ipairs(partIds) do
table.insert(res, resolvePartName(partId, ts, crtCountryId))
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(locationEntityId, ts)
-- (1) see if admin unit needs to be pulled
local uatsEnabled = shouldPullUats(locationEntityId, countryId)
if uatsEnabled > 0 then
-- (2) pull all admin units based on timestamp until reaching nothing, self or country
local allUats = recurseUats(locationEntityId, 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, Wikidata.loadOneValueInChain({locationEntityId, 'P17', 'raw'}))
if not countryId and uatEntitiesIds and #uatEntitiesIds > 0 then
countryId = Wikidata.loadOneValueInChain({uatEntitiesIds[#uatEntitiesIds], 'P17', 'raw'})
end
if countryId and not TableTools.contains(allPartIds, countryId) then
table.insert(allPartLinks, illWd(countryId, lacData.countryNameOverrides[countryId]))
end
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