Відмінності між версіями «Модуль:Wikidata/Places»

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
[перевірена версія][перевірена версія]
м (Відкинуто редагування Andriy.v (обговорення) до зробленого Shmurak)
(Мітка: Відкіт)
 
(Не показані 7 проміжних версій 4 користувачів)
Рядок 1: Рядок 1:
local categorizeByPlaceOfBirthAndDeath = true;
+
local categorizeByPlace = true;
   
 
local WDS = require( 'Module:WikidataSelectors' );
 
local WDS = require( 'Module:WikidataSelectors' );
 
local Flags = require( 'Module:Wikidata/Flags' );
 
local Flags = require( 'Module:Wikidata/Flags' );
local p = {};
+
local p = {
  +
config = {
local project = 'ukwiki';
 
  +
hideSameLabels = false,
  +
hidePartOfLabels = false,
  +
hideUnitsForCapitals = true,
  +
reverseOrder = false,
  +
}
  +
};
   
 
local function min( prev, next )
 
local function min( prev, next )
if ( prev == nil ) then return next;
+
if prev == nil then
elseif ( prev > next ) then return next;
+
return next;
else return prev; end
+
elseif prev > next then
  +
return next;
  +
else
  +
return prev;
  +
end
 
end
 
end
   
 
local function max( prev, next )
 
local function max( prev, next )
if ( prev == nil ) then return next;
+
if prev == nil then
elseif ( prev < next ) then return next;
+
return next;
else return prev; end
+
elseif prev < next then
  +
return next;
  +
else
  +
return prev;
  +
end
 
end
 
end
   
 
local function getTimeBoundariesFromProperty( context, propertyId )
 
local function getTimeBoundariesFromProperty( context, propertyId )
mw.log( 'Get time boundaries for ' .. propertyId .. '...');
 
 
 
local dateClaims = WDS.filter( context.entity.claims, propertyId );
 
local dateClaims = WDS.filter( context.entity.claims, propertyId );
if ( not dateClaims or #dateClaims == 0 ) then return nil; end
+
if not dateClaims or #dateClaims == 0 then
  +
return nil;
mw.log( 'Get time boundaries for ' .. propertyId .. '... Got ' .. #dateClaims .. ' date claim(s)');
 
  +
end
   
 
-- only support exact date so far, but need improvment
 
-- only support exact date so far, but need improvment
Рядок 29: Рядок 42:
 
local right = nil;
 
local right = nil;
 
for _, claim in pairs( dateClaims ) do
 
for _, claim in pairs( dateClaims ) do
if ( not claim.mainsnak ) then return nil; end
+
if not claim.mainsnak then return nil; end
 
local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak );
 
local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak );
if ( not boundaries ) then return nil; end
+
if not boundaries then return nil; end
 
left = min( left, boundaries[ 1 ] );
 
left = min( left, boundaries[ 1 ] );
 
right = max( right, boundaries[ 2 ] );
 
right = max( right, boundaries[ 2 ] );
 
end
 
end
   
if ( not left or not right ) then return nil; end
+
if not left or not right then return nil; end
   
mw.log( 'Time boundaries for ' .. propertyId .. ' are ' .. left .. ' and ' .. right );
 
 
return { left, right };
 
return { left, right };
 
end
 
end
Рядок 57: Рядок 69:
 
local left = nil;
 
local left = nil;
 
local right = nil;
 
local right = nil;
if ( statement.qualifiers and statement.qualifiers[qualifierId] ) then
+
if statement.qualifiers and statement.qualifiers[qualifierId] then
 
for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do
 
for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do
 
local boundaries = context.parseTimeBoundariesFromSnak( qualifier );
 
local boundaries = context.parseTimeBoundariesFromSnak( qualifier );
if ( not boundaries ) then return nil; end
+
if not boundaries then return nil; end
 
left = min( left, boundaries[1] );
 
left = min( left, boundaries[1] );
 
right = max( right, boundaries[2] );
 
right = max( right, boundaries[2] );
Рядок 66: Рядок 78:
 
end
 
end
   
if ( not left or not right ) then
+
if not left or not right then
 
return nil;
 
return nil;
 
end
 
end
Рядок 73: Рядок 85:
 
end
 
end
   
local function getParentsInBoundariesSnakImpl( context, entity, boundaries, propertyIds )
+
local function getParentsInBoundariesSnakImpl( context, entityId, boundaries, propertyIds, selectors )
 
local results = {};
 
local results = {};
   
Рядок 79: Рядок 91:
 
return results;
 
return results;
 
end
 
end
  +
  +
for _, propertyId in ipairs( propertyIds ) do
  +
if (not string.match( propertyId, '^P%d+$' )) then error('Incorrect propertyId: ' + propertyId); end
  +
local selector;
  +
if (selectors ~= nil) then
  +
selector = selectors[propertyId] or propertyId;
  +
else
  +
selector = propertyId;
  +
end
   
  +
local entityClaims = {};
if entity.claims then
 
for _, propertyId in ipairs( propertyIds ) do
+
entityClaims[propertyId] = mw.wikibase.getAllStatements( entityId, propertyId );
  +
local filteredClaims = WDS.filter( entity.claims, propertyId .. '[rank:preferred, rank:normal]' );
 
  +
local filteredClaims = WDS.filter( entityClaims, selector .. '[rank:preferred, rank:normal]' );
if filteredClaims then
 
for _, claim in pairs( filteredClaims ) do
+
if filteredClaims then
  +
for _, claim in pairs( filteredClaims ) do
if not boundaries or not propertyIds or #propertyIds == 0 then
 
  +
if not boundaries or not propertyIds or #propertyIds == 0 then
  +
table.insert( results, claim.mainsnak );
  +
else
  +
local startBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P580' );
  +
local endBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P582' );
  +
  +
if ( startBoundaries == nil or startBoundaries[2] <= boundaries[1] ) and
  +
( endBoundaries == nil or endBoundaries[1] >= boundaries[2] )
  +
then
 
table.insert( results, claim.mainsnak );
 
table.insert( results, claim.mainsnak );
else
+
end
local startBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P580' );
 
local endBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P582' );
 
 
if ( (startBoundaries == nil or startBoundaries[2] <= boundaries[1] )
 
and ( endBoundaries == nil or endBoundaries[1] >= boundaries[2] ) ) then
 
table.insert( results, claim.mainsnak );
 
end
 
end
 
 
end
 
end
 
end
 
end
  +
end
   
if #results > 0 then
+
if #results > 0 then
break;
+
break;
end
 
 
end
 
end
 
end
 
end
Рядок 108: Рядок 130:
 
end
 
end
   
local function getParentsInBoundariesSnak( context, entity, boundaries )
+
local function getParentsInBoundariesSnak( context, entityId, boundaries )
if ( not entity ) then error('entity must be specified'); end
+
if not entityId then error('entityId must be specified'); end
if ( type(entity) ~= 'table' ) then error('entity must be table'); end
+
if type(entityId) ~= 'string' then error('entityId must be string'); end
if ( not boundaries ) then error('boundaries must be specified'); end
+
if not boundaries then error('boundaries must be specified'); end
if ( type(boundaries) ~= 'table' ) then error('boundaries must be table'); end
+
if type(boundaries) ~= 'table' then error('boundaries must be table'); end
   
local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {'P17'} ) -- country
+
local results = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P131'} ) -- located in
  +
if not results or #results == 0 then
  +
results = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P17'} ) -- country
  +
end
   
 
for r, result in pairs( results ) do
 
for r, result in pairs( results ) do
Рядок 121: Рядок 146:
 
end
 
end
 
local resultId = result.datavalue.value.id;
 
local resultId = result.datavalue.value.id;
if ( resultId == entity.id ) then
+
if resultId == entityId then
 
return nil;
 
return nil;
 
end
 
end
Рядок 143: Рядок 168:
 
local isCountry = false;
 
local isCountry = false;
 
local isUnion = false;
 
local isUnion = false;
if ( entity
+
if entity and
and entity.claims
+
entity.claims and
and entity.claims.P31 ) then
+
entity.claims.P31
  +
then
 
for c, claim in pairs( entity.claims.P31 ) do
 
for c, claim in pairs( entity.claims.P31 ) do
if ( claim
+
if claim and
and claim.mainsnak
+
claim.mainsnak and
and claim.mainsnak.datavalue
+
claim.mainsnak.datavalue and
and claim.mainsnak.datavalue.value
+
claim.mainsnak.datavalue.value and
and claim.mainsnak.datavalue.value['numeric-id'] ) then
+
claim.mainsnak.datavalue.value.id
  +
then
local typeId = 'Q' .. claim.mainsnak.datavalue.value['numeric-id'];
 
  +
local typeId = claim.mainsnak.datavalue.value.id;
isCountry = isCountry or countries[typeId];
 
isUnion = isUnion or unions[typeId];
+
isCountry = isCountry or countries[ typeId ];
  +
isUnion = isUnion or unions[ typeId ];
 
end
 
end
 
end
 
end
Рядок 161: Рядок 188:
 
end
 
end
   
local function isPartOfNext(prevLabel, nextLabel)
+
local function isPartOfNext( prevLabel, nextLabel )
return (mw.ustring.len(prevLabel) > mw.ustring.len(nextLabel))
+
return ( mw.ustring.len( prevLabel ) > mw.ustring.len( nextLabel ) )
and (mw.ustring.sub( prevLabel, mw.ustring.len(prevLabel) - mw.ustring.len(nextLabel) + 1 ) == nextLabel);
+
and ( mw.ustring.sub( prevLabel, mw.ustring.len( prevLabel ) - mw.ustring.len( nextLabel ) + 1 ) == nextLabel );
 
end
 
end
   
Рядок 169: Рядок 196:
 
function p.formatPlaceWithQualifiers( context, options, statement )
 
function p.formatPlaceWithQualifiers( context, options, statement )
 
local property = mw.ustring.upper( options.property );
 
local property = mw.ustring.upper( options.property );
  +
mw.log( 'formatPlaceWithQualifiers(..., ' .. property .. ')');
 
  +
local actualDateBoundariesProperties = nil;
  +
if property == 'P19' then actualDateBoundariesProperties = {'P569','P570'}; end
  +
if property == 'P20' then actualDateBoundariesProperties = {'P570','P569'}; end
  +
if property == 'P119' then actualDateBoundariesProperties = {'P570','P569'}; end
  +
  +
local boundaries = nil;
  +
if actualDateBoundariesProperties ~= nil then
  +
boundaries = getTimeBoundariesFromProperties( context, actualDateBoundariesProperties );
  +
end
   
 
local entriesToLookupCategory = {};
 
local entriesToLookupCategory = {};
Рядок 176: Рядок 212:
 
local result = '';
 
local result = '';
 
local baseResult = context.formatSnak( options, statement.mainsnak, circumstances );
 
local baseResult = context.formatSnak( options, statement.mainsnak, circumstances );
  +
if not baseResult then
  +
return nil;
  +
end
  +
 
insertFromSnak( statement.mainsnak, entriesToLookupCategory )
 
insertFromSnak( statement.mainsnak, entriesToLookupCategory )
   
 
local hasAdditionalQualifiers = false;
 
local hasAdditionalQualifiers = false;
if ( statement.qualifiers ) then
+
if statement.qualifiers then
  +
--parent divisions
  +
if statement.qualifiers.P131 then
  +
for i, qualifier in ipairs( statement.qualifiers.P131 ) do
  +
local parentOptions = context.cloneOptions( options );
  +
local qualifierEntityId = qualifier.datavalue.value.id;
  +
parentOptions['text'] = getLabel( context, qualifierEntityId, boundaries );
  +
local link = context.formatSnak( parentOptions, qualifier );
  +
  +
if p.config.reverseOrder then
  +
result = link .. ', ' .. result;
  +
else
  +
result = result .. ', ' .. link;
  +
end
  +
insertFromSnak( qualifier, entriesToLookupCategory )
  +
hasAdditionalQualifiers = true;
  +
end
  +
end
  +
 
--country
 
--country
if ( statement.qualifiers.P17 ) then
+
if statement.qualifiers.P17 then
 
for i, qualifier in ipairs( statement.qualifiers.P17 ) do
 
for i, qualifier in ipairs( statement.qualifiers.P17 ) do
result = result .. ', ' .. context.formatSnak( options, qualifier );
+
local parentOptions = context.cloneOptions( options );
  +
local qualifierEntityId = qualifier.datavalue.value.id;
  +
parentOptions[ 'text' ] = getLabel( context, qualifierEntityId, boundaries );
  +
local link = context.formatSnak( parentOptions, qualifier );
  +
  +
if p.config.reverseOrder then
  +
result = link .. ', ' .. result;
  +
else
  +
result = result .. ', ' .. link;
  +
end
 
insertFromSnak( qualifier, entriesToLookupCategory )
 
insertFromSnak( qualifier, entriesToLookupCategory )
 
hasAdditionalQualifiers = true;
 
hasAdditionalQualifiers = true;
Рядок 190: Рядок 257:
 
end
 
end
   
if ( statement.mainsnak
+
if statement.mainsnak and
and statement.mainsnak.datavalue
+
statement.mainsnak.datavalue and
and statement.mainsnak.datavalue.value
+
statement.mainsnak.datavalue.value and
and statement.mainsnak.datavalue.value['numeric-id'] ) then
+
statement.mainsnak.datavalue.value.id
  +
then
local entity = mw.wikibase.getEntity( 'Q' .. statement.mainsnak.datavalue.value['numeric-id'] );
 
  +
local entityId = statement.mainsnak.datavalue.value.id;
 
local parentSnaks = { statement.mainsnak };
 
local parentSnaks = { statement.mainsnak };
local parentEntities = { entity };
+
local parentEntityIds = { entityId };
   
  +
if actualDateBoundariesProperties ~= nil then
local actualDateBoundariesProperty = nil;
 
  +
local filterCapitalOf = {
if ( property == 'P19' ) then actualDateBoundariesProperty = 'P569'; end
 
  +
[ entityId ] = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P1376'} )
if ( property == 'P20' ) then actualDateBoundariesProperty = 'P570'; end
 
  +
};
if ( property == 'P119' ) then actualDateBoundariesProperty = 'P570'; end
 
  +
if boundaries then
if ( actualDateBoundariesProperty ~= nil ) then
 
  +
local entityOptions = context.cloneOptions( options );
local boundaries = getTimeBoundariesFromProperty( context, actualDateBoundariesProperty );
 
if ( boundaries ) then
+
entityOptions['text'] = getLabel( context, entityId, boundaries );
local entityOptions = options;
 
-- local entityOptions = mw.clone( options );
 
entityOptions['text'] = getLabel( context, entity, boundaries );
 
 
baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances );
 
baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances );
   
local parent = entity;
+
local parentId = entityId;
while ( parent ~= nil ) do
+
while parentId ~= nil do
 
-- get parent
 
-- get parent
local newParentSnaks = getParentsInBoundariesSnak( context, parent, boundaries );
+
local newParentSnaks = getParentsInBoundariesSnak( context, parentId, boundaries );
if ( not newParentSnaks or #newParentSnaks == 0 ) then
+
if not newParentSnaks or #newParentSnaks == 0 then
parent = nil;
+
parentId = nil;
elseif ( #newParentSnaks == 1 ) then
+
elseif #newParentSnaks == 1 then
local parentSnak = newParentSnaks[1];
+
local parentSnak = newParentSnaks[ 1 ];
parent = mw.wikibase.getEntity( 'Q' .. parentSnak.datavalue.value['numeric-id'] );
+
parentId = parentSnak.datavalue.value.id;
  +
 
table.insert( parentSnaks, parentSnak );
 
table.insert( parentSnaks, parentSnak );
table.insert( parentEntities, parent );
+
table.insert( parentEntityIds, parentId );
  +
filterCapitalOf[ parentId ] = getParentsInBoundariesSnakImpl( context, parentId, boundaries, { 'P1376' } );
 
else
 
else
parent = nil;
+
parentId = nil;
result = result .. '[[Категорія:Вікіпедія:Сторінки з неоднозначними геоланками]]';
 
 
end
 
end
 
end
 
end
   
if ( not hasAdditionalQualifiers ) then
+
if not hasAdditionalQualifiers then
for i=2,#parentSnaks,1 do
+
for i = 2, #parentSnaks, 1 do
local parentSnak = parentSnaks[i];
+
local parentSnak = parentSnaks[ i ];
 
insertFromSnak( parentSnak, entriesToLookupCategory )
 
insertFromSnak( parentSnak, entriesToLookupCategory )
 
end
 
end
 
end
 
end
   
-- mw.logObject( parentSnaks );
 
 
do
 
do
 
local i = #parentSnaks;
 
local i = #parentSnaks;
while ( i > 1 ) do
+
while i > 1 do
local prevEntity = parentEntities[i - 1];
+
local prevEntityId = parentEntityIds[ i - 1 ];
 
-- TODO: use English labels, if there is no current language labels
 
-- TODO: use English labels, if there is no current language labels
local prevLabel = getLabel( context, prevEntity, boundaries ) or '';
+
local prevLabel = getLabel( context, prevEntityId, boundaries ) or '';
local nextEntity = parentEntities[i];
+
local nextEntityId = parentEntityIds[ i ];
local nextLabel = getLabel( context, nextEntity, boundaries ) or '';
+
local nextLabel = getLabel( context, nextEntityId, boundaries ) or '';
if ( prevLabel == nextLabel ) then
+
if p.config and p.config.hideSameLabels == true and prevLabel == nextLabel then
 
-- do not output same label twice (NY, NY, USA)
 
-- do not output same label twice (NY, NY, USA)
 
table.remove( parentSnaks, i );
 
table.remove( parentSnaks, i );
table.remove( parentEntities, i );
+
table.remove( parentEntityIds, i );
elseif ( isPartOfNext( prevLabel, ' ' .. nextLabel ) ) then
+
elseif p.config and p.config.hidePartOfLabels == true and isPartOfNext( prevLabel, ' ' .. nextLabel ) then
 
-- do not output same label if it's part of previos
 
-- do not output same label if it's part of previos
 
table.remove( parentSnaks, i - 1 );
 
table.remove( parentSnaks, i - 1 );
table.remove( parentEntities, i - 1 );
+
table.remove( parentEntityIds, i - 1 );
  +
elseif p.config and p.config.hideUnitsForCapitals == true then
  +
-- do not ouput items whose capital is the first item
  +
local capitalId = nil;
  +
for _capitalId, capitalSnaks in pairs( filterCapitalOf ) do
  +
if #capitalSnaks > 0 then
  +
for __, capitalSnak in pairs( capitalSnaks ) do
  +
if parentSnaks[ i ].datavalue.value.id == capitalSnak.datavalue.value.id then
  +
capitalId = _capitalId;
  +
break;
  +
end
  +
end
  +
end
  +
end
  +
if capitalId ~= nil then
  +
if i == #parentSnaks then
  +
i = i - 1;
  +
end
  +
while i > 1 and parentEntityIds[ i ] ~= capitalId do
  +
table.remove( parentSnaks, i );
  +
table.remove( parentEntityIds, i );
  +
i = i - 1;
  +
end
  +
end
 
end
 
end
 
i = i - 1;
 
i = i - 1;
Рядок 256: Рядок 344:
 
end
 
end
   
if ( isSkipTopLevel( parentEntities[ #parentEntities ] ) ) then
+
if isSkipTopLevel( parentEntityIds[ #parentEntityIds ] ) then
table.remove( parentSnaks, #parentEntities );
+
table.remove( parentSnaks, #parentEntityIds );
table.remove( parentEntities, #parentEntities );
+
table.remove( parentEntityIds, #parentEntityIds );
 
end
 
end
   
if ( not hasAdditionalQualifiers ) then
+
if not hasAdditionalQualifiers then
for i=2,#parentSnaks,1 do
+
for i = 2, #parentSnaks, 1 do
local parentSnak = parentSnaks[i];
+
local parentSnak = parentSnaks[ i ];
   
local parentOptions = options;
+
local parentOptions = context.cloneOptions( options );
-- local parentOptions = mw.clone( options );
+
parentOptions['text'] = getLabel( context, parentEntityIds[ i ], boundaries );
parentOptions['text'] = getLabel( context, parentEntities[i], boundaries );
 
   
  +
if p.config.reverseOrder then
result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak );
 
  +
result = context.formatSnak( parentOptions, parentSnak ) .. ', ' .. result;
  +
else
  +
result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak );
  +
end
 
end
 
end
 
end
 
end
Рядок 276: Рядок 367:
 
end
 
end
   
if ( options['thisLocationOnly'] ) then
+
if options[ 'thisLocationOnly' ] then
 
result = baseResult .. context.formatRefs( options, statement );
 
result = baseResult .. context.formatRefs( options, statement );
  +
elseif p.config.reverseOrder then
  +
result = result .. baseResult .. context.formatRefs( options, statement );
 
else
 
else
 
result = baseResult .. result .. context.formatRefs( options, statement );
 
result = baseResult .. result .. context.formatRefs( options, statement );
 
end
 
end
   
  +
if categorizeByPlace then
if ( categorizeByPlaceOfBirthAndDeath ) then
 
if ( property == 'P19' ) then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end
+
if property == 'P19' then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end
if ( property == 'P20' ) then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end
+
if property == 'P20' then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end
if ( property == 'P119' ) then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end
+
if property == 'P119' then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end
 
end
 
end
   
Рядок 293: Рядок 386:
 
-- append entity id from snak to result
 
-- append entity id from snak to result
 
function insertFromSnak( snak, result )
 
function insertFromSnak( snak, result )
if ( not categorizeByPlaceOfBirthAndDeath ) then
+
if not categorizeByPlace then
 
return;
 
return;
 
end
 
end
if ( snak
+
if snak and
and snak.datavalue
+
snak.datavalue and
and snak.datavalue.type == 'wikibase-entityid'
+
snak.datavalue.type == 'wikibase-entityid' and
and snak.datavalue.value
+
snak.datavalue.value and
and snak.datavalue.value['entity-type'] == 'item' ) then
+
snak.datavalue.value[ 'entity-type' ] == 'item'
  +
then
table.insert( result, 'Q' .. snak.datavalue.value['numeric-id'] );
 
  +
table.insert( result, snak.datavalue.value.id );
 
end
 
end
 
end
 
end
   
function getCategory( propertyToSearch, entriesToLookupCategoryFor )
+
function getCategory( propertyId, entriesToLookupCategoryFor )
 
for _, placeId in pairs( entriesToLookupCategoryFor ) do
 
for _, placeId in pairs( entriesToLookupCategoryFor ) do
local placeEntity = mw.wikibase.getEntity( placeId );
+
local claims = mw.wikibase.getBestStatements(placeId, propertyId);
local claims = WDS.filter( placeEntity.claims, propertyToSearch );
 
   
if ( claims ) then
+
if claims then
 
for _, claim in pairs( claims ) do
 
for _, claim in pairs( claims ) do
if ( claim.mainsnak
+
if claim.mainsnak and
and claim.mainsnak
+
claim.mainsnak and
and claim.mainsnak.datavalue
+
claim.mainsnak.datavalue and
and claim.mainsnak.datavalue.type == "wikibase-entityid" ) then
+
claim.mainsnak.datavalue.type == 'wikibase-entityid'
  +
then
local catEntityId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
 
local catEntity = mw.wikibase.getEntity( catEntityId );
+
local catEntityId = claim.mainsnak.datavalue.value.id;
  +
local catSitelink = mw.wikibase.getSitelink(catEntityId);
if ( catEntity and catEntity.sitelinks and catEntity.sitelinks[project] and catEntity.sitelinks[project].title ) then
 
  +
if (catSitelink) then
return '[[' .. catEntity.sitelinks[project].title .. ']]';
 
  +
return '[[' .. catSitelink .. ']]';
 
end
 
end
 
end
 
end
Рядок 327: Рядок 421:
 
return '';
 
return '';
 
end
 
end
  +
  +
  +
local historicNamesProperties = { 'P1813', 'P1448', 'P1705' };
  +
  +
local langCode = mw.language.getContentLanguage():getCode();
  +
local historicNamesPropertySelectors = {
  +
P1813 = 'P1813[language:' .. langCode .. ']',
  +
P1448 = 'P1448[language:' .. langCode .. ']',
  +
P1705 = 'P1705[language:' .. langCode .. ']'
  +
};
   
 
-- get current of historic name of place
 
-- get current of historic name of place
function getLabel( context, entity, boundaries )
+
function getLabel( context, entityId, boundaries )
if not entity then
+
if not entityId then
 
return nil;
 
return nil;
 
end
 
end
  +
if (type(entityId) ~= 'string') then error('incorrect type of entityId argument'); end;
 
local lang = mw.language.getContentLanguage();
 
local langCode = lang:getCode();
 
   
 
-- name from label
 
-- name from label
  +
local label = mw.wikibase.getLabel( entityId );
-- TODO: lang:getFallbackLanguages()
 
local label = nil;
 
if entity.labels then
 
if entity.labels[langCode] and entity.labels[langCode].value then
 
label = entity.labels[langCode].value;
 
elseif entity.labels.en and entity.labels.en.value then
 
label = entity.labels.en.value;
 
end
 
end
 
   
 
-- name from properties
 
-- name from properties
local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {
+
local results = getParentsInBoundariesSnakImpl( context, entityId, boundaries,
  +
historicNamesProperties, historicNamesPropertySelectors);
'P1813[language:' .. langCode .. ']',
 
'P1448[language:' .. langCode .. ']',
 
'P1705[language:' .. langCode .. ']'
 
} );
 
   
 
for r, result in pairs( results ) do
 
for r, result in pairs( results ) do
if result.datavalue
+
if result.datavalue and
and result.datavalue.value
+
result.datavalue.value and
and result.datavalue.value.text then
+
result.datavalue.value.text
  +
then
 
label = result.datavalue.value.text;
 
label = result.datavalue.value.text;
 
break;
 
break;
Рядок 370: Рядок 462:
   
 
local function calculateEndDateTimestamp( context, options, statement )
 
local function calculateEndDateTimestamp( context, options, statement )
if (not context) then error('context not specified') end;
+
if not context then error( 'context not specified' ) end;
if (not options) then error('options not specified') end;
+
if not options then error( 'options not specified' ) end;
if (not options.entity) then error('options.entity missing') end;
+
if not options.entity then error( 'options.entity missing' ) end;
if (not statement) then error('statement not specified') end;
+
if not statement then error( 'statement not specified' ) end;
   
if ( statement.qualifiers and statement.qualifiers.P582 ) then
+
if statement.qualifiers and statement.qualifiers.P582 then
for i, qualifier in ipairs(statement.qualifiers.P582 ) do
+
for i, qualifier in ipairs( statement.qualifiers.P582 ) do
 
local parsedTime = context.parseTimeFromSnak( qualifier );
 
local parsedTime = context.parseTimeFromSnak( qualifier );
if ( parsedTime ) then
+
if parsedTime then
 
return parsedTime;
 
return parsedTime;
 
end
 
end
Рядок 385: Рядок 477:
   
 
-- check death day... do we have it at all?
 
-- check death day... do we have it at all?
for h, propertyId in pairs( { "P570", "P577", "P571" } ) do
+
for h, propertyId in pairs( { "P570", "P577", "P576" } ) do
 
local dateClaims = context.selectClaims( options, propertyId );
 
local dateClaims = context.selectClaims( options, propertyId );
if ( dateClaims ) then
+
if dateClaims then
 
for i, statement in ipairs( dateClaims ) do
 
for i, statement in ipairs( dateClaims ) do
 
local parsedTime = context.parseTimeFromSnak( statement.mainsnak );
 
local parsedTime = context.parseTimeFromSnak( statement.mainsnak );
if ( parsedTime ) then
+
if parsedTime then
 
return parsedTime;
 
return parsedTime;
 
end
 
end
Рядок 404: Рядок 496:
   
 
function p.formatCountryClaimWithFlag( context, options, statement )
 
function p.formatCountryClaimWithFlag( context, options, statement )
if (not context) then error('context not specified') end;
+
if not context then error('context not specified') end;
if (not options) then error('options not specified') end;
+
if not options then error('options not specified') end;
if (not options.entity) then error('options.entity is missing') end;
+
if not options.entity then error('options.entity is missing') end;
if (not statement) then error('statement not specified') end;
+
if not statement then error('statement not specified') end;
   
  +
if not statement.mainsnak or
local countryEntityId = nil;
 
  +
not statement.mainsnak.datavalue or
local countryEntity = nil;
 
if ( statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value["numeric-id"] ) then
+
not statement.mainsnak.datavalue.value or
countryEntityId = 'Q' .. statement.mainsnak.datavalue.value["numeric-id"];
+
not statement.mainsnak.datavalue.value.id
  +
then
countryEntity = mw.wikibase.getEntity( countryEntityId );
 
  +
local result = context.formatStatementDefault( context, options, statement );
  +
if not result then
  +
return '';
  +
end
  +
return '<span class="country-name">' .. result .. '</span>';
 
end
 
end
 
 
  +
local countryEntityId = statement.mainsnak.datavalue.value.id;
if not countryEntity then
 
return '<span class="country-name">' .. context.formatStatementDefault( context, options, statement ) .. '</span>';
 
end
 
 
 
local endDateTimestamp = calculateEndDateTimestamp( context, options, statement );
 
local endDateTimestamp = calculateEndDateTimestamp( context, options, statement );
 
local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} );
 
local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} );
   
local countryOptions = mw.clone( options );
+
local countryOptions = context.cloneOptions( options );
 
if not countryOptions['text'] or countryOptions['text'] == '' then
 
if not countryOptions['text'] or countryOptions['text'] == '' then
countryOptions['text'] = getLabel( context, countryEntity, boundaries );
+
countryOptions['text'] = getLabel( context, countryEntityId, boundaries );
 
end
 
end
   
 
local flag = Flags.getFlag( context, countryEntityId, endDateTimestamp );
 
local flag = Flags.getFlag( context, countryEntityId, endDateTimestamp );
if ( flag ) then
+
if flag then
return flag .. '&nbsp;<span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>';
+
return flag .. '&nbsp;<span class="country-name">' ..
  +
context.formatStatementDefault( context, countryOptions, statement ) ..
  +
'</span>';
 
end
 
end
   
return '<span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>';
+
return '<span class="country-name">' ..
  +
context.formatStatementDefault( context, countryOptions, statement ) ..
  +
'</span>';
 
end
 
end
   

Поточна версія на 16:35, 10 вересня 2018

{{Модуль:Wikidata/Places}} (і·о·д·р··#) містить функції форматування для Властивостей (claims), які є посиланнями на географічні сутності (зазвичай — адміністративні одиниці).


Вызов всех функций данного шаблона осуществляется из шаблона {{wikidata}}. Функции модуля нельзя вызывать напрямую — они передаются в виде аргументов из соответствующих связанных шаблонов (и только из них, в другие шаблоны их также вставлять не нужно).

formatPlaceWithQualifiers[ред. код]

...

Категорії підтримки[ред. код]

CC-logo.svg

Цей модуль містить код, запозичений з модуля «Wikidata/Places» російської Вікіпедії.

Переклад

local categorizeByPlace = true;

local WDS = require( 'Module:WikidataSelectors' );
local Flags = require( 'Module:Wikidata/Flags' );
local p = {
	config = {
		hideSameLabels = false,
		hidePartOfLabels = false,
		hideUnitsForCapitals = true,
		reverseOrder = false,
	}
};

local function min( prev, next )
	if prev == nil then
		return next;
	elseif prev > next then
		return next;
	else
		return prev;
	end
end

local function max( prev, next )
	if prev == nil then
		return next;
	elseif prev < next then
		return next;
	else
		return prev;
	end
end

local function getTimeBoundariesFromProperty( context, propertyId )
	local dateClaims = WDS.filter( context.entity.claims, propertyId );
	if not dateClaims or #dateClaims == 0 then
		return nil;
	end

	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;
	for _, claim in pairs( dateClaims ) do
		if not claim.mainsnak then return nil; end
		local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak );
		if not boundaries then return nil; end
		left = min( left, boundaries[ 1 ] );
		right = max( right, boundaries[ 2 ] );
	end

	if not left or not right then return nil; end

	return { left, right };
end

local function getTimeBoundariesFromProperties( context, propertyIds )
	for _, propertyId in ipairs( propertyIds ) do
		local result = getTimeBoundariesFromProperty( context, propertyId );
		if result then
			return result;
		end
	end

	return nil;
end

local function getTimeBoundariesFromQualifiers( context, statement, qualifierId )
	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;
	if statement.qualifiers and statement.qualifiers[qualifierId] then
		for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do
			local boundaries = context.parseTimeBoundariesFromSnak( qualifier );
			if not boundaries then return nil; end
			left = min( left, boundaries[1] );
			right = max( right, boundaries[2] );
		end
	end

	if not left or not right then
		return nil;
	end

	return { left, right };
end

local function getParentsInBoundariesSnakImpl( context, entityId, boundaries, propertyIds, selectors )
	local results = {};

	if not propertyIds or #propertyIds == 0 then
		return results;
	end
	
	for _, propertyId in ipairs( propertyIds ) do
		if (not string.match( propertyId, '^P%d+$' )) then error('Incorrect propertyId: ' + propertyId); end
		local selector;
		if (selectors ~= nil) then
			selector = selectors[propertyId] or propertyId;
		else
			selector = propertyId;
		end

		local entityClaims = {};
		entityClaims[propertyId] = mw.wikibase.getAllStatements( entityId, propertyId );

		local filteredClaims = WDS.filter( entityClaims, selector .. '[rank:preferred, rank:normal]' );
		if filteredClaims then
			for _, claim in pairs( filteredClaims ) do
				if not boundaries or not propertyIds or #propertyIds == 0 then
					table.insert( results, claim.mainsnak );
				else
					local startBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P580' );
					local endBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P582' );
		
					if ( startBoundaries == nil or startBoundaries[2] <= boundaries[1] ) and
						( endBoundaries == nil or endBoundaries[1] >= boundaries[2] )
					then
						table.insert( results, claim.mainsnak );
					end 
				end
			end
		end

		if #results > 0 then
			break;
		end
	end

	return results;
end

local function getParentsInBoundariesSnak( context, entityId, boundaries )
	if not entityId then error('entityId must be specified'); end
	if type(entityId) ~= 'string' then error('entityId must be string'); end
	if not boundaries then error('boundaries must be specified'); end
	if type(boundaries) ~= 'table' then error('boundaries must be table'); end

	local results = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P131'} ) -- located in
	if not results or #results == 0 then
		results = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P17'} ) -- country
	end

	for r, result in pairs( results ) do
		if result.snaktype ~= 'value' then
			return nil;
		end
		local resultId = result.datavalue.value.id;
		if resultId == entityId then
			return nil;
		end
	end
	return results;
end

local unions = { 
	Q1140229 = true, -- political union
	Q3623811 = true, -- Экономический союз
	Q4120211 = true -- региональная организация
}

local countries = {
	Q6256 = true, -- страна
	Q7275 = true, -- государство
	Q3624078 = true -- суверенное государство
}

local function isSkipTopLevel( entity )
	local isCountry = false;
	local isUnion = false;
	if entity and
		entity.claims and
		entity.claims.P31
	then
		for c, claim in pairs( entity.claims.P31 ) do
			if claim and
				claim.mainsnak and
				claim.mainsnak.datavalue and
				claim.mainsnak.datavalue.value and
				claim.mainsnak.datavalue.value.id
			then
				local typeId = claim.mainsnak.datavalue.value.id;
				isCountry = isCountry or countries[ typeId ];
				isUnion = isUnion or unions[ typeId ];
			end
		end
	end
	return isUnion and not isCountry;
end

local function isPartOfNext( prevLabel, nextLabel )
	return ( mw.ustring.len( prevLabel ) > mw.ustring.len( nextLabel ) )
		and ( mw.ustring.sub( prevLabel, mw.ustring.len( prevLabel ) - mw.ustring.len( nextLabel ) + 1 ) == nextLabel );
end

--Property:P19, Property:P20, Property:P119
function p.formatPlaceWithQualifiers( context, options, statement )
	local property = mw.ustring.upper( options.property );

	local actualDateBoundariesProperties = nil;
	if property == 'P19' then actualDateBoundariesProperties = {'P569','P570'}; end
	if property == 'P20' then actualDateBoundariesProperties = {'P570','P569'}; end
	if property == 'P119' then actualDateBoundariesProperties = {'P570','P569'}; end

	local boundaries = nil;
	if actualDateBoundariesProperties ~= nil then
		boundaries = getTimeBoundariesFromProperties( context, actualDateBoundariesProperties );
	end

	local entriesToLookupCategory = {};

	local circumstances = context.getSourcingCircumstances( statement );
	local result = '';
	local baseResult = context.formatSnak( options, statement.mainsnak, circumstances );
	if not baseResult then
		return nil;
	end
	
	insertFromSnak( statement.mainsnak, entriesToLookupCategory )

	local hasAdditionalQualifiers = false;
	if statement.qualifiers then
		--parent divisions
		if statement.qualifiers.P131 then
			for i, qualifier in ipairs( statement.qualifiers.P131 ) do
				local parentOptions = context.cloneOptions( options );
				local qualifierEntityId = qualifier.datavalue.value.id;
				parentOptions['text'] = getLabel( context, qualifierEntityId, boundaries );
				local link = context.formatSnak( parentOptions, qualifier );

				if p.config.reverseOrder then
					result = link .. ', ' .. result;
				else
					result = result .. ', ' .. link;
				end
				insertFromSnak( qualifier, entriesToLookupCategory )
				hasAdditionalQualifiers = true;
			end
		end

		--country
		if statement.qualifiers.P17 then
			for i, qualifier in ipairs( statement.qualifiers.P17 ) do
				local parentOptions = context.cloneOptions( options );
				local qualifierEntityId = qualifier.datavalue.value.id;
				parentOptions[ 'text' ] = getLabel( context, qualifierEntityId, boundaries );
				local link = context.formatSnak( parentOptions, qualifier );

				if p.config.reverseOrder then
					result = link .. ', ' .. result;
				else
					result = result .. ', ' .. link;
				end
				insertFromSnak( qualifier, entriesToLookupCategory )
				hasAdditionalQualifiers = true;
			end
		end
	end

	if statement.mainsnak and
		statement.mainsnak.datavalue and
		statement.mainsnak.datavalue.value and
		statement.mainsnak.datavalue.value.id
	then
		local entityId = statement.mainsnak.datavalue.value.id;
		local parentSnaks = { statement.mainsnak };
		local parentEntityIds = { entityId };

		if actualDateBoundariesProperties ~= nil then
			local filterCapitalOf = {
				[ entityId ] = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P1376'} )
			};
			if boundaries then
				local entityOptions = context.cloneOptions( options );
				entityOptions['text'] = getLabel( context, entityId, boundaries );
				baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances );

				local parentId = entityId;
				while parentId ~= nil do
					-- get parent
					local newParentSnaks = getParentsInBoundariesSnak( context, parentId, boundaries );
					if not newParentSnaks or #newParentSnaks == 0 then
						parentId = nil;
					elseif #newParentSnaks == 1 then
						local parentSnak = newParentSnaks[ 1 ];
						parentId = parentSnak.datavalue.value.id;

						table.insert( parentSnaks, parentSnak );
						table.insert( parentEntityIds, parentId );
						filterCapitalOf[ parentId ] = getParentsInBoundariesSnakImpl( context, parentId, boundaries, { 'P1376' } );
					else
						parentId = nil;
					end
				end

				if not hasAdditionalQualifiers then
					for i = 2, #parentSnaks, 1 do
						local parentSnak = parentSnaks[ i ];
						insertFromSnak( parentSnak, entriesToLookupCategory )
					end
				end

				do
					local i = #parentSnaks;
					while i > 1 do
						local prevEntityId = parentEntityIds[ i - 1 ];
						-- TODO: use English labels, if there is no current language labels
						local prevLabel = getLabel( context, prevEntityId, boundaries ) or '';
						local nextEntityId = parentEntityIds[ i ];
						local nextLabel = getLabel( context, nextEntityId, boundaries ) or '';
						if p.config and p.config.hideSameLabels == true and prevLabel == nextLabel then
							-- do not output same label twice (NY, NY, USA)
							table.remove( parentSnaks, i );
							table.remove( parentEntityIds, i );
						elseif p.config and p.config.hidePartOfLabels == true and isPartOfNext( prevLabel, ' ' .. nextLabel ) then
							-- do not output same label if it's part of previos
							table.remove( parentSnaks, i - 1 );
							table.remove( parentEntityIds, i - 1 );
						elseif p.config and p.config.hideUnitsForCapitals == true then
							-- do not ouput items whose capital is the first item
							local capitalId = nil;
							for _capitalId, capitalSnaks in pairs( filterCapitalOf ) do
								if #capitalSnaks > 0 then
									for __, capitalSnak in pairs( capitalSnaks ) do
										if parentSnaks[ i ].datavalue.value.id == capitalSnak.datavalue.value.id then
											capitalId = _capitalId;
											break;
										end
									end
								end
							end
							if capitalId ~= nil then
								if i == #parentSnaks then
									i = i - 1;
								end
								while i > 1 and parentEntityIds[ i ] ~= capitalId do
									table.remove( parentSnaks, i );
									table.remove( parentEntityIds, i );
									i = i - 1;
								end
							end
						end
						i = i - 1;
					end
				end

				if isSkipTopLevel( parentEntityIds[ #parentEntityIds ] ) then
					table.remove( parentSnaks, #parentEntityIds );
					table.remove( parentEntityIds, #parentEntityIds );
				end

				if not hasAdditionalQualifiers then
					for i = 2, #parentSnaks, 1 do
						local parentSnak = parentSnaks[ i ];

						local parentOptions = context.cloneOptions( options );
						parentOptions['text'] = getLabel( context, parentEntityIds[ i ], boundaries );

						if p.config.reverseOrder then
							result = context.formatSnak( parentOptions, parentSnak ) .. ', ' .. result;
						else
							result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak );
						end
					end
				end
			end
		end
	end

	if options[ 'thisLocationOnly' ] then
		result = baseResult  .. context.formatRefs( options, statement );
	elseif p.config.reverseOrder then
		result = result .. baseResult .. context.formatRefs( options, statement );
	else
		result = baseResult .. result .. context.formatRefs( options, statement );
	end

	if categorizeByPlace then
		if property == 'P19' then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end
		if property == 'P20' then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end
		if property == 'P119' then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end
	end

	return result;
end

-- append entity id from snak to result
function insertFromSnak( snak, result )
	if not categorizeByPlace then
		return;
	end
	if snak and
		snak.datavalue and
		snak.datavalue.type == 'wikibase-entityid' and
		snak.datavalue.value and
		snak.datavalue.value[ 'entity-type' ] == 'item'
	then
		table.insert( result, snak.datavalue.value.id );
	end
end

function getCategory( propertyId, entriesToLookupCategoryFor )
	for _, placeId in pairs( entriesToLookupCategoryFor ) do
		local claims = mw.wikibase.getBestStatements(placeId, propertyId);

		if claims then
			for _, claim in pairs( claims ) do
				if claim.mainsnak and
					claim.mainsnak and
					claim.mainsnak.datavalue and
					claim.mainsnak.datavalue.type == 'wikibase-entityid'
				then
					local catEntityId = claim.mainsnak.datavalue.value.id;
					local catSitelink = mw.wikibase.getSitelink(catEntityId);
					if (catSitelink) then
						return '[[' .. catSitelink .. ']]';
					end
				end
			end
		end
	end
	return '';
end


local historicNamesProperties = { 'P1813', 'P1448', 'P1705' };

local langCode = mw.language.getContentLanguage():getCode();
local historicNamesPropertySelectors = {
		P1813 = 'P1813[language:' .. langCode .. ']',
		P1448 = 'P1448[language:' .. langCode .. ']',
		P1705 = 'P1705[language:' .. langCode .. ']'
};

-- get current of historic name of place
function getLabel( context, entityId, boundaries )
	if not entityId then
		return nil;
	end
	if (type(entityId) ~= 'string') then error('incorrect type of entityId argument'); end;

	-- name from label
	local label = mw.wikibase.getLabel( entityId );

	-- name from properties
	local results = getParentsInBoundariesSnakImpl( context, entityId, boundaries,
		historicNamesProperties, historicNamesPropertySelectors);

	for r, result in pairs( results ) do
		if result.datavalue and
			result.datavalue.value and
			result.datavalue.value.text
		then
			label = result.datavalue.value.text;
			break;
		end
	end

	return label;
end

p.getLabel = getLabel;

local function calculateEndDateTimestamp( context, options, statement )
	if not context then error( 'context not specified' ) end;
	if not options then error( 'options not specified' ) end;
	if not options.entity then error( 'options.entity missing' ) end;
	if not statement then error( 'statement not specified' ) end;

	if statement.qualifiers and statement.qualifiers.P582 then
		for i, qualifier in ipairs( statement.qualifiers.P582 ) do
			local parsedTime = context.parseTimeFromSnak( qualifier );
			if parsedTime then
				return parsedTime;
			end
		end
	end

	-- check death day... do we have it at all?
	for h, propertyId in pairs( { "P570", "P577", "P576" } ) do
		local dateClaims = context.selectClaims( options, propertyId );
		if dateClaims then
			for i, statement in ipairs( dateClaims ) do
				local parsedTime = context.parseTimeFromSnak( statement.mainsnak );
				if parsedTime then
					return parsedTime;
				end
			end
		end
	end

	-- TODO: check other "end" properties

	-- no death day
	return os.time() * 1000;
end

function p.formatCountryClaimWithFlag( context, options, statement )
	if not context then error('context not specified') end;
	if not options then error('options not specified') end;
	if not options.entity then error('options.entity is missing') end;
	if not statement then error('statement not specified') end;

	if not statement.mainsnak or
		not statement.mainsnak.datavalue or
		not statement.mainsnak.datavalue.value or
		not statement.mainsnak.datavalue.value.id
	then
		local result = context.formatStatementDefault( context, options, statement );
		if not result then
			return '';
		end
		return '<span class="country-name">' .. result .. '</span>';
	end
	
	local countryEntityId = statement.mainsnak.datavalue.value.id;
	local endDateTimestamp = calculateEndDateTimestamp( context, options, statement );
	local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} );

	local countryOptions = context.cloneOptions( options );
	if not countryOptions['text'] or countryOptions['text'] == '' then
		countryOptions['text'] = getLabel( context, countryEntityId, boundaries );
	end

	local flag = Flags.getFlag( context, countryEntityId, endDateTimestamp );	
	if flag then
		return flag .. '&nbsp;<span class="country-name">' ..
			context.formatStatementDefault( context, countryOptions, statement ) ..
			'</span>';
	end

	return '<span class="country-name">' ..
		context.formatStatementDefault( context, countryOptions, statement ) ..
		'</span>';
end

return p;