Модуль:Wikidata/date Документація модуля[перегляд] [редагувати] [історія] [очистити кеш]
--settings
local categoryUnknownBirthDate = '[[Категорія:Персоналії без дати народження]]';
local categoryUnknownDeathDate = '[[Категорія:Персоналії без дати смерті]]';
local categoryBigCurrentAge = '[[Категорія:Статті про персоналії з великим поточним віком]]'
local nowLabel = 'тепер. час'
local moduleDates = require( "Module:Dates" )
local moduleWikidata = require( "Module:Wikidata" )
local moduleDatetime = require( "Module:Datetime" )
function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
-- accepts table of time+precision values
function ageCurrent ( bTable )
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined!
for bKey, bValue in pairs(bTable) do
if ( bValue.unknown ) then
return nil
end
local bStructure = bValue.structure
local bPrecision = bValue.precision
local dStructure = os.date( "*t" )
local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, 11 )
if ( possibleAge == "NYA" ) then
possibleAge = calculatedAge
else
if ( possibleAge ~= calculatedAge ) then
possibleAge = nil
end
end
end
return possibleAge
end
-- accepts tables of time+precision values
function age ( bTable, dTable )
local possibleAge = "NYA" -- it meansm "Not Yet Assigned", not what you imagined!
for bKey, bValue in pairs( bTable ) do
if ( bValue.unknown ) then
return nil
end
local bStructure = bValue.structure
local bPrecision = bValue.precision
for dKey, dValue in pairs( dTable ) do
if ( dValue.unknown ) then
return nil
end
local dStructure = dValue.structure
local dPrecision = dValue.precision
if ( bValue.calendar == 'julian' and dValue.calendar == 'gregorian' ) then
-- to calculate age, need to adjust bStructure to gregorian calendar
local shift = math.floor(bStructure.year/100-2) - math.floor(bStructure.year/400)
-- TODO: re-implement this properly
bStructure.day = bStructure.day + shift
end
local calculatedAge = ageImpl ( bStructure, bPrecision, dStructure, dPrecision )
if ( possibleAge == "NYA" ) then
possibleAge = calculatedAge
else
if ( possibleAge ~= calculatedAge ) then
possibleAge = nil
end
end
end
end
return possibleAge
end
function ageImpl ( bStructure, bPrecision, dStructure, dPrecision )
if ( not bStructure or not dStructure or bPrecision < 10 or dPrecision < 10 ) then
return nil
end
local shift = 0;
if ( bStructure.year < 0 and dStructure.year > 0 ) then
shift = -1;
end
if ( bPrecision == 10 or dPrecision == 10 ) then
if ( bStructure.month < dStructure.month ) then
return dStructure.year - bStructure.year + shift
end
if ( bStructure.month == dStructure.month ) then
return nil
end
if ( bStructure.month > dStructure.month ) then
return dStructure.year - bStructure.year - 1 + shift
end
end
if ( bStructure.month < dStructure.month ) then
return dStructure.year - bStructure.year + shift
end
if ( bStructure.month == dStructure.month ) then
if ( bStructure.day <= dStructure.day ) then
return dStructure.year - bStructure.year + shift
else
return dStructure.year - bStructure.year - 1 + shift
end
end
if ( bStructure.month > dStructure.month ) then
return dStructure.year - bStructure.year - 1 + shift
end
return nil
end
-- returns table of time+precision values for specified property
function parseProperty ( context, options, propertyId )
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 propertyId ) then error( 'propertyId not specified'); end;
local claims = context.selectClaims( options, propertyId );
if not claims then
return nil
end
local result = {}
for key, claim in pairs( claims ) do
table.insert ( result, parseClaim( claim ) );
end
return result
end
function parseClaim ( claim )
if ( claim.mainsnak.snaktype == "value" ) then
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601.
local timeISO8601 = string.gsub( string.gsub( tostring( claim.mainsnak.datavalue.value.time ), '-00%-', '-01-' ), '-00T', '-01T' )
local unixtime = parseISO8601( timeISO8601 )
local structure = os.date("*t", unixtime)
local precision = tonumber( claim.mainsnak.datavalue.value.precision )
local calendarmodel = 'gregorian';
if (mw.ustring.find(claim.mainsnak.datavalue.value.calendarmodel, 'Q1985786', 1, true)) then
calendarmodel = 'julian';
end
local item = { structure=structure, precision=precision, calendar = calendarmodel }
return item;
elseif ( claim.mainsnak.snaktype == "novalue" ) then
-- novalue
return { unknown="novalue" };
else
--unknown
return { unknown="unknown" };
end
end
-- перевірка на співпадаючі дати з різною моделлю календаря
function checkDupDates( t )
if #t > 1 then
local removed = false;
local j = 1;
-- перевірка на співпадаючі дати з різною моделлю календаря
while (j <= #t) do
local i = 1;
while (i <= #t) do
if i ~= j then
if (os.time(t[j].structure) == os.time(t[i].structure)) then
if ((t[j].calendarmodel == 'gregorian') and
(t[i].calendarmodel == 'julian')) then
removed = true;
break;
else
table.remove(t, i)
end
else
i = i + 1;
end
else
i = i + 1;
end
end
if removed then
removed = false;
table.remove(t, j);
else
j = j+1;
end
end
end
end
-- returns first qualifier of specified propertyId
function getQualifierDataValue( statement, qualifierPropertyId )
if ( statement.qualifiers
and statement.qualifiers[qualifierPropertyId] ) then
local qualifiers = statement.qualifiers[qualifierPropertyId];
for _, qualifier in ipairs( qualifiers ) do
if (qualifier.datavalue) then
return qualifier.datavalue;
end
end
end
return nil;
end
local p = {}
function p.formatDateOfBirthClaim( 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;
local qNotSoonerThan = getQualifierDataValue( statement, 'P1319' );
local qNotLaterThan = getQualifierDataValue( statement, 'P1326' );
if ( qNotSoonerThan or qNotLaterThan ) then
local results = {};
if ( qNotSoonerThan ) then
table.insert( results, 'не раніше ' .. formatDateImpl( qNotSoonerThan.value, {}, nil, nil ) );
end
if ( qNotLaterThan ) then
table.insert( results, 'не пізніше ' .. formatDateImpl( qNotLaterThan.value, {}, nil, nil ) );
end
return mw.text.listToText( results, ' і ' , ' і ' );
end
options['conjunction'] = ' або ';
options['value-module'] = 'Wikidata/date';
options['value-function'] = 'formatBirthDate';
options.i18n.somevalue = '\'\'невідомо\'\'';
options.i18n.circa = '<span style="border-bottom: 1px dotted; cursor: help;" title="близько">бл. </span>';
local result = context.formatStatementDefault( context, options, statement );
local bTable = { parseClaim( statement ) };
local dTable = parseProperty ( context, options, 'P570' ) or options.dvalue --dvalue містить параметр дата смерті, що взятий з картки, а не з вікіданих
if ( bTable and not dTable ) then
local age = ageCurrent( bTable )
if ( age ) then
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'uk' ):plural( age, 'рік', 'роки', 'років') .. ')</span>'
if ( not options.nocat ) then
if ( age > 150 ) then
result = result .. categoryBigCurrentAge;
end
end
end
end
return result;
end
function p.formatDateOfDeathClaim( 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;
local qNotSoonerThan = getQualifierDataValue( statement, 'P1319' );
local qNotLaterThan = getQualifierDataValue( statement, 'P1326' );
if ( qNotSoonerThan or qNotLaterThan ) then
local results = {};
if ( qNotSoonerThan ) then
table.insert( results, 'не раніше ' .. formatDateImpl( qNotSoonerThan.value, {}, nil, nil ) );
end
if ( qNotLaterThan ) then
table.insert( results, 'не пізніше ' .. formatDateImpl( qNotLaterThan.value, {}, nil, nil ) );
end
return mw.text.listToText( results, ' і ' , ' і ' );
end
options['conjunction'] = ' або ';
options['value-module'] = 'Wikidata/date';
options['value-function'] = 'formatDeathDate';
options.i18n.somevalue = '\'\'невідомо\'\'';
options.i18n.circa = '<span style="border-bottom: 1px dotted; cursor: help;" title="близько">бл. </span>';
local result = context.formatStatementDefault( context, options, statement );
local bTable = parseProperty ( context, options, 'P569' )
local dTable = { parseClaim( statement ) };
if ( bTable and dTable ) then
local age = age( bTable, dTable )
if ( age ) then
result = result .. ' <span style="white-space:nowrap;">(' .. age .. ' ' .. mw.language.new( 'uk' ):plural( age, 'рік', 'роки', 'років') .. ')</span>'
end
end
return result;
end
function p.formatDateWithout( 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;
local qNotSoonerThan = getQualifierDataValue( statement, 'P1319' );
local qNotLaterThan = getQualifierDataValue( statement, 'P1326' );
if ( qNotSoonerThan or qNotLaterThan ) then
local results = {};
if ( qNotSoonerThan ) then
table.insert( results, 'не раніше ' .. formatDateImpl( qNotSoonerThan.value, {}, nil, nil ) );
end
if ( qNotLaterThan ) then
table.insert( results, 'не пізніше ' .. formatDateImpl( qNotLaterThan.value, {}, nil, nil ) );
end
return mw.text.listToText( results, ' і ' , ' і ' );
end
options['conjunction'] = ' або ';
options['value-module'] = 'Wikidata/date';
options['value-function'] = 'formatDeathDate';
options.i18n.somevalue = '\'\'невідомо\'\'';
options.i18n.circa = '<span style="border-bottom: 1px dotted; cursor: help;" title="близько">бл. </span>';
local result = context.formatStatementDefault( context, options, statement );
return result;
end
-- Reentry point for Wikidata Snak formatting
function p.formatBirthDate( context, options, value )
if ( not context ) then error( 'context not specified'); end;
if ( not options ) then error( 'options not specified'); end;
if ( not value ) then error( 'value not specified'); end;
if ( options.nocat ) then
return formatDateImpl( value, options, 'bday', nil )
else
return formatDateImpl( value, options, 'bday', 'Народились' )
end
end
-- Reentry point for Wikidata Snak formatting
function p.formatDeathDate( context, options, value )
if ( not context ) then error( 'context not specified'); end;
if ( not options ) then error( 'options not specified'); end;
if ( not value ) then error( 'value not specified'); end;
if ( options.nocat and options.nocat ~= '' ) then
return formatDateImpl( value, options, 'dday', nil )
else
return formatDateImpl( value, options, 'dday', 'Померли' )
end
end
-- Reentry point for Wikidata Snak formatting -- default one
function p.formatDate( context, options, value )
if ( not context ) then error( 'context not specified'); end;
if ( not options ) then error( 'options not specified'); end;
if ( not value ) then error( 'value not specified'); end;
local microformatClass = options.microformat or nil;
if ( options.nocat and options.nocat ~= '' ) then
return formatDateImpl( value, options, microformatClass, nil )
else
local categoryPrefix = options.categoryPrefix or nil;
return formatDateImpl( value, options, microformatClass, categoryPrefix )
end
end
function p.formatDateIntervalProperty( context, options )
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;
-- Получение нужных утверждений
local WDS = require( 'Module:WikidataSelectors' );
local fromProperty = options.property
if options.from and options.from ~= '' then
fromProperty = options.from
end
local fromClaims = WDS.filter( options.entity.claims, fromProperty );
local toClaims = WDS.filter( options.entity.claims, options.to );
local withinClaims = WDS.filter( options.entity.claims, options.within );
if fromClaims == nil and toClaims == nil then
return ''
end
local formattedFromClaims = {}
if fromClaims then
for i, claim in ipairs( fromClaims ) do
local formattedStatement = context.formatStatement( options, claim )
if formattedStatement then
formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
table.insert( formattedFromClaims, formattedStatement )
end
end
end
local formattedToClaims = {}
local toOptions = deepcopy( options )
toOptions.property = options.to
toOptions.novalue = nowLabel
if toClaims then
for i, claim in ipairs( toClaims ) do
local formattedStatement = context.formatStatement( toOptions, claim )
if formattedStatement then
formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( toOptions.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
table.insert( formattedToClaims, formattedStatement )
end
end
end
local out = ''
local fromOut = mw.text.listToText( formattedFromClaims, options.separator, options.conjunction )
local toOut = mw.text.listToText( formattedToClaims, options.separator, options.conjunction )
if fromOut ~= '' or toOut ~= '' then
if fromOut ~= '' then
out = fromOut
else
out = '?'
end
if toOut ~= '' then
out = out .. ' — ' .. toOut
else
if withinClaims ~= nil then
out = 'з ' .. out
else
out = out .. ' — ' .. nowLabel
end
end
end
if out ~= '' then
if options.before then
out = options.before .. out
end
if options.after then
out = out .. options.after
end
end
return out
end
function formatDateImpl( value, options, microformatClass, categoryPrefix )
if ( not value ) then error( 'value not specified'); end;
if ( not options ) then error( 'options not specified'); end;
-- The calendar model used for saving the data is always the proleptic Gregorian calendar according to ISO 8601.
local timeISO8601 = string.gsub( string.gsub( tostring( value.time ), '-00%-', '-01-' ), '-00T', '-01T' )
local unixtime = parseISO8601( timeISO8601 )
if not unixtime then
return ''
end
local structure = os.date("*t", unixtime)
local precision = tonumber( value.precision )
if precision == 6 then
return formatMillenium(structure, categoryPrefix)
end
if precision == 7 then
return formatCentury(structure, categoryPrefix)
end
if precision == 8 then
return p.formatDecade(structure, categoryPrefix)
end
if precision == 9 then
local tCopy = deepcopy( structure )
tCopy.day = nil
tCopy.month = nil
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix)
end
-- year and month only
if precision == 10 then
local tCopy = deepcopy( structure )
tCopy.day = nil
return moduleDates.formatWikiImpl(tCopy, tCopy, infoclass, categoryPrefix)
end
local calendarmodel = 'gregorian';
if (mw.ustring.find(value.calendarmodel, 'Q1985786', 1, true)) then
calendarmodel = 'julian';
end
if (calendarmodel == 'gregorian') then
return moduleDates.formatWikiImpl( structure, structure, microformatClass, categoryPrefix )
else
return p.formatAsJulian( unixtime, infoclass, categoryPrefix )
end
end
function p.formatDecade( time, categoryNamePrefix )
if ( time.year < 0 ) then
local decadeLink = moduleDatetime._decadeLink(math.floor((time.year - 1) / 10))
local century = math.floor( (math.abs( time.year) - 1) / 100 ) + 1;
if ( categoryNamePrefix ) then
return decadeLink .. '[[Category:' .. categoryNamePrefix .. ' у ' .. century .. ' столітті до н. е.]]'
else
return decadeLink
end
else
local decadeLink = moduleDatetime._decadeLink(math.floor(time.year / 10))
local century = math.floor( (time.year - 1) / 100 ) + 1;
if ( categoryNamePrefix ) then
return decadeLink .. '[[Category:' .. categoryNamePrefix .. ' у ' .. century .. ' столітті]]'
else
return decadeLink;
end
end
end
function formatCentury( time, categoryNamePrefix )
if ( time.year < 0 ) then
local century = math.floor( (math.abs( time.year) - 1) / 100 ) + 1;
if ( categoryNamePrefix ) then
return '[[' .. century .. ' століття до н. е.]][[Category:' .. categoryNamePrefix .. ' у ' .. century .. ' столітті до н. е.]]'
else
return '[[' .. century .. ' століття до н. е.]]'
end
else
local century = math.floor( (time.year - 1) / 100 ) + 1;
if ( categoryNamePrefix ) then
return '[[' .. century .. ' століття]][[Category:' .. categoryNamePrefix .. ' у ' .. century .. ' столітті]]'
else
return '[[' .. century .. ' століття]]'
end
end
end
function formatMillenium( time, categoryNamePrefix )
local moduleRoman = require( "Module:RomanNumber" )
if ( time.year < 0 ) then
local millenium = math.floor( (math.abs( time.year) - 1) / 1000 ) + 1;
if ( categoryNamePrefix ) then
return '[[' .. millenium .. ' тисячоліття до н. е.]][[Category:' .. categoryNamePrefix .. ' у ' .. millenium .. ' тисячолітті до н. е.]]'
else
return '[[' .. millenium .. ' тисячоліття до н. е.]]'
end
else
local millenium = math.floor( (time.year - 1) / 1000 ) + 1;
if ( moduleRoman ) then
millenium = moduleRoman.toRomanNumber( millenium );
end
end
end
function parseISO8601Date(str)
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
local Y, M, D = mw.ustring.match( str, pattern )
return tonumber(Y), tonumber(M), tonumber(D)
end
function parseISO8601Time(str)
local pattern = "T(%d+):(%d+):(%d+)%Z"
local H, M, S = mw.ustring.match( str, pattern)
return tonumber(H), tonumber(M), tonumber(S)
end
function parseISO8601Offset(str)
if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
local pattern = "([-+])(%d%d):?(%d?%d?)$"
local sign, oh, om = mw.ustring.match( str, pattern)
sign, oh, om = sign or "+", oh or "00", om or "00"
return tonumber(sign .. oh), tonumber(sign .. om)
end
function parseISO8601(str)
if 'table' == type(str) then
if str.args and str.args[1] then
str = '' .. str.args[1]
else
return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str )
end
end
local Y,M,D = parseISO8601Date(str)
local h,m,s = parseISO8601Time(str)
local oh,om = parseISO8601Offset(str)
if not Y or not M or not D or not h or not m or not s or not oh or not om then
return nil
end
return tonumber(os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s}))
end
local lowestBoundary = parseISO8601('-900-02-20T00:00:00Z')
local mainBoundary = parseISO8601('1582-10-05T00:00:00Z')
local lastBoundary = parseISO8601('1918-01-31T00:00:00Z');
boundaries = {
-- from (G) till next will be diff(G = J + diff), at current
{ lowestBoundary, -9 },
{ parseISO8601('-700-02-29T00:00:00Z'), -8 },
{ parseISO8601('-600-02-29T00:00:00Z'), -7 },
{ parseISO8601('-500-02-29T00:00:00Z'), -6 },
{ parseISO8601('-300-02-29T00:00:00Z'), -5 },
{ parseISO8601('-200-02-29T00:00:00Z'), -4 },
{ parseISO8601('-100-02-29T00:00:00Z'), -3 },
{ parseISO8601('0000-00-00T00:00:00Z'), -2 },
{ parseISO8601('0100-02-29T00:00:00Z'), -1 },
{ parseISO8601('0200-02-29T00:00:00Z'), 0 },
{ parseISO8601('0300-02-29T00:00:00Z'), 1 },
{ parseISO8601('0500-02-29T00:00:00Z'), 2 },
{ parseISO8601('0600-02-29T00:00:00Z'), 3 },
{ parseISO8601('0700-02-29T00:00:00Z'), 4 },
{ parseISO8601('0900-02-29T00:00:00Z'), 5 },
{ parseISO8601('1000-02-29T00:00:00Z'), 6 },
{ parseISO8601('1100-02-29T00:00:00Z'), 7 },
{ parseISO8601('1300-02-29T00:00:00Z'), 8 },
{ parseISO8601('1400-02-29T00:00:00Z'), 9 },
{ parseISO8601('1500-02-29T00:00:00Z'), 10 },
{ parseISO8601('1700-02-29T00:00:00Z'), 11 },
{ parseISO8601('1800-02-29T00:00:00Z'), 12 },
{ parseISO8601('1900-02-29T00:00:00Z'), 13 },
{ lastBoundary, '' },
};
-- Переданий час має бути за Юліанським календарем (старим стилем)
function p.formatAsJulian( julTime, infocardClass, categoryNamePrefix )
if 'table' == type( julTime ) then
if julTime.args and julTime.args[1] then
julTime = tonumber( julTime.args[1] )
else
return 'unknown argument type: ' .. type( julTime ) .. ': ' .. table.tostring( julTime )
end
end
local t = os.date( "*t", julTime )
if ( julTime <= lowestBoundary ) then
return "''неправильна дата (досяжна точність)''";
end
if ( julTime >= lastBoundary ) then
return "''неправильна дата (юліанський не використовується після 1918-01-26)''";
end
for i=1,#boundaries,1 do
local b1 = boundaries[i][1];
local b2 = boundaries[i + 1][1];
if ( b1 <= julTime and julTime < b2 ) then
local b1s = os.date( "*t", b1 )
if ( b1s.year == t.year and b1s.month == t.month and b1s.day == t.day) then
if ( julTime < mainBoundary ) then
-- only julian
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, {year=t.year, month=2, day=29}, infocardClass, categoryNamePrefix );
else
--julian and grigorian
return moduleDates.formatWikiImpl( {year=t.year, month=2, day=29}, t, infocardClass, categoryNamePrefix )
end
else
local gregTime = os.date( "*t", julTime + boundaries[i][2] * 24 * 60 * 60 );
if ( julTime < mainBoundary ) then
-- only julian
return moduleDates.formatWikiImpl( t, t, infocardClass, categoryNamePrefix );
else
--julian and grigorian
return moduleDates.formatWikiImpl( t, gregTime, infocardClass, categoryNamePrefix )
end
end
end
end
if ( julTime >= lastBoundary ) then
return "''помилка у модулі Модуль:Wikidata/date (не знайдений зсув конвертації календаря)''";
end
end
return p
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia