Модуль:WD: различия между версиями

Материал из Тептар — свободной энциклопедии
Перейти к навигации Перейти к поиску
(Новая страница: «local wd = { -- ---------------------------------------------------------------------------------------------------------- -- Константы ET_xxx (entity types) -- ET_ITEM = "item", ET_PROPERTY = "property", ET_STATEMENT = "statement", -- ---------------------------------------------------------------------------------------------------------- -- Константы DT_xxx (data types) -- DT_ITEM = "wikibase-item", -- "datavalue":...»)
(нет различий)

Версия от 12:01, 7 февраля 2022

Назначение

В модуле собираются сервисные фукнции, связанные с чтением Тептар данных.

Функции, доступные из Тептар-разметки

label()

Описание

Возвращает метку свойства или элемента Тептар данных на указанном языке. Если на указанном языке метки нет, возвращается метка на английском. Если нет метки и на английском, возвращается «нет метки» (константа MSG_NO_LABEL). Если указать несуществующее свойство или элемент Тептар данных, будет сгенерирована ошибка Lua (см. константы ERRMSG_PROPERTY_NOT_FOUND, ERRMSG_ITEM_NOT_FOUND и ERRMSG_ENTITY_NOT_FOUND). Для элементов-перенаправлений возвращается метка элемента, на который оно указывает.
Функция используется в шаблоне {{WD label}}.

Использование

{{#invoke:WD|label|идентификатор|язык}}

Параметры:

  • идентификатор — идентификатор свойства (Pxxx или pxxx) или элемента Тептар данных (Qxxx или qxxx);
  • язык — двухбуквенный код языка (ru, en, de и т. д.).

Примеры для свойств:

  • {{#invoke:WD|label|P569|ru}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P569|en}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P569|de}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P569|la}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P97|ru}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P97|en}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|P97|la}} (нет метки на латыни) → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).

Примеры для элементов:

  • {{#invoke:WD|label|Q2|ru}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|Q2|en}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|Q2|de}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|Q2|la}} → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|label|Q8258093|ru}} (перенаправление Q8258093 → Q6305566) → Ошибка Lua на строке 295: attempt to index field 'wikibase' (a nil value).

Примеры ошибок:

  • {{#invoke:WD|label|P999999|ru}} (несуществующее свойство) → ошибка Lua «свойство P999999 не найдено»
  • {{#invoke:WD|label|Q6|ru}} (несуществующий элемент) → ошибка Lua «элемент Q6 не найден»
  • {{#invoke:WD|label|BOND007|ru}} (неверный идентификатор) → ошибка Lua «Введённый идентификатор не известен системе. Используйте один из действующих идентификаторов сущностей»

description()

Описание

Возвращает описание свойства или элемента Тептар данных на указанном языке. Если на указанном языке описания нет, возвращается описание на английском. Если нет описания и на английском, возвращается «нет описания» (константа MSG_NO_DESCRIPTION). Если указать несуществующее свойство или элемент Тептар данных, будет сгенерирована ошибка Lua (см. константы ERRMSG_PROPERTY_NOT_FOUND, ERRMSG_ITEM_NOT_FOUND и ERRMSG_ENTITY_NOT_FOUND). Для элементов-перенаправлений возвращается описание элемента, на который оно указывает.
Функция используется в шаблоне {{WD description}}.

Использование

{{#invoke:WD|description|идентификатор|язык}}

Параметры:

  • идентификатор — идентификатор свойства (Pxxx или pxxx) или элемента Тептар данных (Qxxx или qxxx);
  • язык — двухбуквенный код языка (ru, en, de и т. д.).

Примеры для свойств:

  • {{#invoke:WD|description|P569|ru}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|P569|en}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|P569|de}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|P97|ru}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|P97|en}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|P97|la}} (нет описания на латыни) → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).

Примеры для элементов:

  • {{#invoke:WD|description|Q2|ru}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|Q2|en}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|Q2|de}} → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|Q2|la}} (нет описания на латыни) → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|description|Q8258093|ru}} (перенаправление Q8258093 → Q6305566) → Ошибка Lua на строке 311: attempt to index field 'wikibase' (a nil value).

Примеры ошибок:

  • {{#invoke:WD|description|P999999|ru}} (несуществующее свойство) → ошибка Lua «свойство P999999 не найдено»
  • {{#invoke:WD|description|Q6|ru}} (несуществующий элемент) → ошибка Lua «элемент Q6 не найден»
  • {{#invoke:WD|description|BOND007|ru}} (неверный идентификатор) → ошибка Lua «Введённый идентификатор не известен системе. Используйте один из действующих идентификаторов сущностей»

datatype()

Описание

Возвращает тип данных свойства Тептар данных (одно из значений констант DT_xxx). Если свойство не найдено или функции передан идентификатор элемента, генерируется ошибка Lua (константа ERRMSG_PROPERTY_NOT_FOUND).

Использование

{{#invoke:WD|datatype|идентификатор}}

Примеры:

  • {{#invoke:WD|datatype|P31}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P1687}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P304}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P1476}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P18}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P854}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P569}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P625}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|datatype|P2067}} → Ошибка Lua на строке 326: attempt to index field 'wikibase' (a nil value).

Примеры ошибок:

  • {{#invoke:WD|datatype|P999999}} (несуществующее свойство) → ошибка Lua «свойство P999999 не найдено»
  • {{#invoke:WD|datatype|Q2}} (элемент) → ошибка Lua «свойство Q2 не найдено»
  • {{#invoke:WD|datatype|BOND007}} (неверный идентификатор) → ошибка Lua «Введённый идентификатор не известен системе. Используйте один из действующих идентификаторов сущностей»

format_property()

Описание

Для указанного свойства Тептар данных возвращает ссылку на него в виде [[:d:Property:Pxxx|<метка> (Pxxx)]] с меткой на указанном языке. Если на указанном языке метки нет, используется метка на английском. Если нет метки и на английском, вместо неё используется «нет метки». Если свойство не найдено или функции передан идентификатор элемента, генерируется ошибка Lua (константа ERRMSG_PROPERTY_NOT_FOUND).
Функция используется в шаблоне {{WD property}}

Использование

{{#invoke:WD|format_property|идентификатор|язык}}

Параметры:

  • идентификатор — идентификатор свойства Тептар данных (Pxxx или pxxx);
  • язык — двухбуквенный код языка (ru, en, de и т. д.).

Примеры:

  • {{#invoke:WD|format_property|P569|ru}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P569|en}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P569|de}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P569|la}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P97|ru}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P97|en}} → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_property|P97|la}} (нет метки на латыни) → Ошибка Lua на строке 450: attempt to index field 'wikibase' (a nil value).

Примеры ошибок:

  • {{#invoke:WD|format_property|P999999|ru}} (несуществующее свойство) → ошибка Lua «свойство P999999 не найдено»
  • {{#invoke:WD|format_property|Q2|ru}} (не свойство) → ошибка Lua «свойство Q2 не найдено»
  • {{#invoke:WD|format_property|BOND007|ru}} (неверный идентификатор) → ошибка Lua «Введённый идентификатор не известен системе. Используйте один из действующих идентификаторов сущностей»

format_item()

Описание

Для указанного элемента Тептар данных возвращает ссылку на него в виде [[:d:Qxxx|<метка> (Qxxx)]] с меткой на указанном языке. Если на указанном языке метки нет, используется метка на английском. Если нет метки и на английском, вместо неё используется «нет метки». Если элемент не найден или функции передан идентификатор свойства, генерируется ошибка Lua (константа ERRMSG_ITEM_NOT_FOUND). Для элементов-перенаправлений возвращается ссылка метка и идентификатор на того элемента, на который оно указывает.
Функция используется в шаблоне {{WD item}}.

Использование

{{#invoke:WD|format_item|идентификатор|язык}}

Параметры:

  • идентификатор — идентификатор элемента Тептар данных (Qxxx или qxxx);
  • язык — двухбуквенный код языка (ru, en, de и т. д.).

Примеры:

  • {{#invoke:WD|format_item|Q2|ru}} → Ошибка Lua на строке 480: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_item|Q2|en}} → Ошибка Lua на строке 480: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_item|Q2|de}} → Ошибка Lua на строке 480: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_item|Q2|la}} → Ошибка Lua на строке 480: attempt to index field 'wikibase' (a nil value).
  • {{#invoke:WD|format_item|Q8258093|ru}} (перенаправление Q8258093 → Q6305566) → Ошибка Lua на строке 480: attempt to index field 'wikibase' (a nil value).

Примеры ошибок:

  • {{#invoke:WD|format_item|Q6|ru}} (несуществующий элемент) → ошибка Lua «элемент Q6 не найден»
  • {{#invoke:WD|format_item|P569|ru}} (не элемент) → ошибка Lua «элемент P569 не найден»
  • {{#invoke:WD|format_item|BOND007|ru}} (неверный идентификатор) → ошибка Lua «Введённый идентификатор не известен системе. Используйте один из действующих идентификаторов сущностей»

dump_entity()

Описание

Отладочная функция, позволяющая показать значение в формате JSON, возвращаемое функцией mw.wikibase.getEntityObject() для указанного элемента или свойства Тептар данных.

Использование

{{#invoke:WD|dump_entity|идентификатор}}

Параметр:

  • идентификатор — идентификатор свойства (Pxxx или pxxx) или элемента Тептар данных (Qxxx или qxxx).

Примеры (из-за объёмности вывода результат не показан, чтобы увидеть его, используйте Служебная:Песочница для шаблонов):

  • {{#invoke:WD|dump_entity|P569}}
  • {{#invoke:WD|dump_entity|Q2188189}}

dump_sitelinks()

Описание

Отладочная функция, позволяющая показать ссылки в формате JSON для указанного элемента Тептар данных.

Использование

{{#invoke:WD|dump_sitelinks|идентификатор}}

Параметр:

  • идентификатор — идентификатор элемента Тептар данных (Qxxx или qxxx).

Пример:

Вызов Результат
{{#invoke:WD|dump_sitelinks|Q15920521}} Ошибка Lua на строке 550: attempt to index field 'wikibase' (a nil value).
{{#invoke:WD|dump_sitelinks|Q4100335}}
{{#invoke:WD|dump_sitelinks|Q644102}}

dump_statements()

Описание

Отладочная функция, позволяющая показать утверждения данного свойства в формате JSON для указанного элемента или свойства Тептар данных.

Использование

{{#invoke:WD|dump_statements|идентификатор|свойство}}

Параметры:

  • идентификатор — идентификатор свойства (Pxxx или pxxx) или элемента Тептар данных (Qxxx или qxxx);
  • свойство — идентификатор свойства (Pxxx или pxxx), значение которого надо показать.

Примеры:

Вызов Результат
{{#invoke:WD|dump_statements|Q359|P856}}
{{#invoke:WD|dump_statements|P527|P1696}} Ошибка Lua на строке 589: attempt to index field 'wikibase' (a nil value).
{{#invoke:WD|dump_statements|Q15920521|P1476}} Ошибка Lua на строке 589: attempt to index field 'wikibase' (a nil value).
{{#invoke:WD|dump_statements|Q4100335|P570}}

Функции, доступные из других модулей

is_property()

is_item()

is_statement()

get_statement_value()

get_item_id()

get_item_qid()

has_valid_item_value()

get_label()

get_description()

get_sitelink()

get_sitelink_by_lang()

table_to_string()


local wd = {
--
----------------------------------------------------------------------------------------------------------
-- Константы ET_xxx	(entity types)
--
ET_ITEM       = "item",
ET_PROPERTY   = "property",
ET_STATEMENT  = "statement",
--
----------------------------------------------------------------------------------------------------------
-- Константы DT_xxx	(data types)
--
DT_ITEM       = "wikibase-item",        --  "datavalue": { "value": { "numeric-id": 1551807, "entity-type": "item" }, "type": "wikibase-entityid" }
DT_PROPERTY   = "wikibase-property",    --  "datavalue": { "value": { "numeric-id": 1753, "entity-type": "property" }, "type": "wikibase-entityid" }
DT_DATETIME   = "time",                 --  "datavalue": { "value": { "before": 0, "time": "+2013-10-28T00:00:00Z", "timezone": 0, "precision": 11, "after": 0,
                                        --                            "calendarmodel": "http://www.wikidata.org/entity/Q1985727"},
                                        --                 "type": "time"}
DT_COMMONS    = "commonsMedia",         --  "datavalue": { "value": "Turgenev by Repin.jpg", "type": "string" }, "datatype": "commonsMedia" }
DT_STRING     = "string",               --  "datavalue": { "value": "/m/04j_pj", "type": "string" }
DT_URL        = "url",                  --  "datavalue": { "value": "http://www.acme.com/", "type": "string" }
DT_ML_STRING  = "monolingualtext",      --  "datavalue": { "value": { "language": "ru", "text": "Накануне" }, "type": "monolingualtext" }
DT_COORD      = "globe-coordinate",     --  "datavalue": { "value": { "longitude": 30.352547, "precision": 1e-05,
                                        --                            "globe": "http://www.wikidata.org/entity/Q2", "latitude": 59.943044 },
                                        --                 "type": "globecoordinate" }
DT_QUANTITY   = "quantity",             --  "datavalue": { "value": { "amount": "+103", "upperBound": "+104", "lowerBound": "+102",
                                        --                            "unit": "http://www.wikidata.org/entity/Q42289" },
                                        --                 "type": "quantity" }
--
----------------------------------------------------------------------------------------------------------
-- Константы VT_xxx	(value types)
--
VT_ENTITY_ID  = "wikibase-entityid",   -- используется для DT_ITEM и DT_PROPERTY
VT_DATETIME   = "time",                -- используется для DT_DATETIME
VT_COORD      = "globecoordinate",     -- используется для DT_COORD
VT_STRING     = "string",              -- используется для DT_STRING, DT_URL и DT_COMMONS
VT_ML_STRING  = "monolingualtext",     -- используется для DT_ML_STRING
VT_QUANTITY   = "quantity",            -- используется для DT_QUANTITY
--
----------------------------------------------------------------------------------------------------------
-- Константы ST_xxx	(snak types)
--
ST_VALUE     = "value",        -- "конкретное значение"
ST_UNKNOWN   = "somevalue",    -- "значение неизвестно"
ST_NO_VALUE  = "novalue",      -- "значение отсутствует"
--
----------------------------------------------------------------------------------------------------------
-- Константы RANK_xxx	(ranks)
--
RANK_NORNAL      = "normal",       -- "нормальный ранг"
RANK_PREFERRED   = "preferred",    -- "предпочтительный ранг"
RANK_DEPRECATED  = "deprecated",   -- "нерекомендуемый ранг"
--
----------------------------------------------------------------------------------------------------------
-- Константы TP_xxx	(time precision)
--
TP_10E8_YEARS  =  1,   -- 100 млн лет
TP_10E7_YEARS  =  2,   -- 10 млн лет
TP_10E6_YEARS  =  3,   -- 1 млн лет
TP_10E5_YEARS  =  4,   -- 100 тыс лет
TP_10E4_YEARS  =  5,   -- 10 тыс лет
TP_10E3_YEARS  =  6,   -- 1 тыс лет
TP_CENTURY     =  7,   -- 100 лет
TP_DECADE      =  8,   -- 10 лет
TP_YEAR        =  9,   -- 1 год
TP_MONTH       = 10,   -- 1 месяц
TP_DAY         = 11,   -- 1 день
--
----------------------------------------------------------------------------------------------------------
-- Константы CM_xxx	(calendar model)
--
CM_GREGORIAN  = "http://www.wikidata.org/entity/Q1985727",  -- пролептический григорианский календарь
CM_JULIAN     = "http://www.wikidata.org/entity/Q1985786",  -- пролептический юлианский календарь
--
----------------------------------------------------------------------------------------------------------
-- Константа GLOBE_xxx	(небесное тело, к которому относятся координаты)
--
GLOBE_EARTH   = "http://www.wikidata.org/entity/Q2",    -- Земля
GLOBE_MOON    = "http://www.wikidata.org/entity/Q405"   -- Луна
--
};
--
----------------------------------------------------------------------------------------------------------
-- Константы
--
local LANG_EN = "en";
local MSG_NO_LABEL = "нет метки";
local MSG_NO_DESCRIPTION = "нет описания";
--
----------------------------------------------------------------------------------------------------------
-- Сообщения об ошибках
--
local ERRMSG_PROPERTY_NOT_FOUND = "свойство %s не найдено";
local ERRMSG_ITEM_NOT_FOUND = "элемент %s не найден";
local ERRMSG_ENTITY_NOT_FOUND = "сущность %s не найдена";
local ERRMSG_CLAIM_NOT_FOUND = "%s не имеет %s";
--
----------------------------------------------------------------------------------------------------------
--
function wd.is_property(entity)
  return (entity ~= nil) and (entity["type"] == wd.ET_PROPERTY);
end;
--
function wd.is_item(entity)
  return (entity ~= nil) and (entity["type"] == wd.ET_ITEM);
end;
--
function wd.is_statement(statement)
  return (statement ~= nil) and (statement["type"] == wd.ET_STATEMENT);
end;
--
function wd.get_statement_value(statement, s_datatype, s_value_type)
  if statement == nil then
    return nil;
  end;
  local snak = statement["mainsnak"];
  if (snak == nil) or (snak["datatype"] ~= s_datatype) or (snak["snaktype"] ~= wd.ST_VALUE) then
    return nil;
  end;
  local datavalue = snak["datavalue"];
  if (datavalue == nil) or (datavalue["type"] ~= s_value_type) then
    return nil;
  end;
  return datavalue["value"];
end;
--
function wd.get_item_id(statement)
  local value = wd.get_statement_value(statement, wd.DT_ITEM, wd.VT_ENTITY_ID);
  if (value == nil) or (value["entity-type"] ~= wd.ET_ITEM) then
    return nil;
  end;
  return value["numeric-id"];
end;
--
function wd.get_item_qid(statement)
  local n_id = wd.get_item_id(statement);
  if n_id == nil then
    return nil;
  else
    return "Q" .. tostring(n_id);
  end;
end;
--
function wd.has_valid_item_value (entity, s_property_id, n_item_id)
  local claim = nil;
  if (entity ~= nil) and (entity.claims ~= nil) then
    claim = entity.claims[s_property_id];
  end;
  if claim ~= nil then
    for key, value in pairs(claim) do
      if (value.rank ~= wd.RANK_DEPRECATED) and (wd.get_item_id(value) == n_item_id) then
      	return true;
      end;
    end;
  end;
  return false;
end;
--
function wd.get_label(entity, s_lang, s_default)
  local s_label = s_default;
  if entity["labels"] ~= nil then
    local l = entity.labels[s_lang];
    if (l == nil) and (s_lang ~= LANG_EN) then
      l = entity.labels[LANG_EN];
    end;
    if l ~= nil then
      s_label = l.value;
    end;
  end;
  return s_label;
end;
--
function wd.get_description(entity, s_lang, s_default)
  local s_description = s_default;
  if entity["descriptions"] ~= nil then
    local l = entity.descriptions[s_lang];
    if (l == nil) and (s_lang ~= LANG_EN) then
      l = entity.descriptions[LANG_EN];
    end;
    if l ~= nil then
      s_description = l.value;
    end;
  end;
  return s_description;
end;
--
----------------------------------------------------------------------------------------------------------
-- Функции для получения ссылки на данный вики-проект в виде (пример для Q644102):
--   { "site": "ruwiki", "title": "Спасо-Преображенский собор (Санкт-Петербург)", "badges": { 1: "Q17437798" } }
-- Если ссылки нет, возвращает nil.
-- Примеры
--   local sitelink = wd.get_sitelink(entity, "ruwiki");
--   local sitelink = wd.get_sitelink_by_lang(entity, "wiki", ["ru", "de", "en"]);
--
function wd.get_sitelink(entity, s_code)
  if entity["sitelinks"] == nil then
    return nil;
  end;
  return entity.sitelinks[s_code];
end;
--
function wd.get_sitelink_by_lang(entity, s_suffix, langs)
  if entity["sitelinks"] == nil then
    return nil;
  end;
  local sitelink = nil;
  for key, s_lang in pairs(langs) do
    sitelink = entity.sitelinks[s_lang .. s_suffix];
    if sitelink ~= nil then
      break;
    end;
  end;
  return sitelink;
end;
--
local map = {
  ruwikisource    = "s:",
  ruwiki          = "",
  ruwikiquote     = "q:",
  ruwikinews      = "n:",
  ruwikivoyage    = "voy:",
  commonswiki     = "commons:",
  wikidatawiki    = "d:",
  specieswiki     = "species:"
};
--
local lang_map = {
  wikisource    = "s:",
  wiki          = "",
  wikiquote     = "q:",
  wikinews      = "n:",
  wikivoyage    = "voy:"
};
--
function wd.map_sitelink_to_prefix(s_site)
  local s_iw_prefix = map[s_site];
  if s_iw_prefix ~= nil then
    return s_iw_prefix;
  end;
  local n_len = mw.ustring.len(s_site);
  for s_suffix, s_iw_prefix in pairs(lang_map) do
    --mw.log("suffix: "..s_suffix);
    --mw.log("interwiki prefix: "..s_iw_prefix);
    local n_suffix_len = mw.ustring.len(s_suffix);
    local n_lang_len = n_len - n_suffix_len;
    if (n_lang_len > 0) and (mw.ustring.sub(s_site, -n_suffix_len) == s_suffix) then
      return s_iw_prefix .. mw.ustring.sub(s_site, 1, n_lang_len) .. ":";
    end;
  end;
  error("Can't map " .. s_site .. " to a interwiki link");
end;
--
--  {{#invoke:WD|map_sitelink|ruwikisource}}
--  {{#invoke:WD|map_sitelink|enwikisource}}
--  {{#invoke:WD|map_sitelink|enwiki}}
--  {{#invoke:WD|map_sitelink|ruwiki}}
function wd.map_sitelink (frame)
  return "[["..wd.map_sitelink_to_prefix(tostring(frame.args[1])).."]]";
end;
--
--  {{#invoke:WD|dump_iwikimap}}
--  {{#invoke:WD|dump_iwikimap|local}}
--  {{#invoke:WD|dump_iwikimap|!local}}
--function wd.dump_iwikimap (frame)
--  return wd.table_to_string(mw.site.interwikiMap(tostring(frame.args[1])), "");
--end;
--
----------------------------------------------------------------------------------------------------------
-- Функция для Шаблон:WD label
-- Возвращает метку элемента или свойства
--
-- Примеры для свойств:
--  {{#invoke:WD|label|P569|ru}}  → дата рождения
--  {{#invoke:WD|label|P569|en}}  → date of birth
--  {{#invoke:WD|label|P569|de}}  → Geburtsdatum
--  {{#invoke:WD|label|P569|la}}  → natus
--
--  {{#invoke:WD|label|P97|ru}}  → титул
--  {{#invoke:WD|label|P97|en}}  → noble title
--  {{#invoke:WD|label|P97|la}}  → noble title (так как метки на латыни нет)
--
--  {{#invoke:WD|label|P999999|ru}}  → ошибка  (несуществующее свойство)
--
-- Примеры для элементов:
--  {{#invoke:WD|label|Q2|ru}} → Земля
--  {{#invoke:WD|label|Q2|en}} → Earth
--  {{#invoke:WD|label|Q2|de}} → Erde
--  {{#invoke:WD|label|Q2|la}} → Tellus
--
--  {{#invoke:WD|label|Q6|ru}} → ошибка  (несуществующий элемент)
--  {{#invoke:WD|label|Q8258093|ru}} → Category:Aquitanians (перенаправление Q8258093 → Q6305566)
--
function wd.label (frame)
  local s_id = tostring(frame.args[1]);
  local s_lang = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if entity == nil then
    if mw.ustring.match(s_id, "[Qq]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_id));
    elseif mw.ustring.match(s_id, "[Pp]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_id));
    else
      error(mw.ustring.format(ERRMSG_ENTITY_NOT_FOUND, s_id));
    end;
  end;
  return wd.get_label(entity, s_lang, MSG_NO_LABEL);
end;
--
function wd.description (frame)
  local s_id = tostring(frame.args[1]);
  local s_lang = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if entity == nil then
    if mw.ustring.match(s_id, "[Qq]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_id));
    elseif mw.ustring.match(s_id, "[Pp]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_id));
    else
      error(mw.ustring.format(ERRMSG_ENTITY_NOT_FOUND, s_id));
    end;
  end;
  return wd.get_description(entity, s_lang, MSG_NO_DESCRIPTION);
end;
--
function wd.datatype (frame)
  local s_id = tostring(frame.args[1]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if (entity == nil) or (not wd.is_property(entity)) then
    error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_id));
  end;
  return entity.datatype;
end;
--
-- [[{{#invoke:WD|sitelink|Q9301454|itwiki}}]]
-- [[{{#invoke:WD|sitelink|Q213141|specieswiki}}]]
-- [[{{#invoke:WD|sitelink|Q213141|commonswiki}}]]
-- [[{{#invoke:WD|sitelink|Q4115189|wikidatawiki}}]]
-- [[{{#invoke:WD|sitelink|Q656|ruwikivoyage}}]]
--
function wd.sitelink (frame)
  local s_item_id = tostring(frame.args[1]);
  local s_code = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_item_id);
  if (entity == nil) or not wd.is_item(entity) then
    error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_item_id));
  end;
  local sitelink = nil;
  local s_lang = frame.args[3];
  if s_lang == nil then    -- если третий параметр не указан, вызываем get_sitelink
    sitelink = wd.get_sitelink(entity, s_code);
  else
    local langs = {}; -- пустой массив
    langs[3] = tostring(s_lang);
    local n_index = 4;
    s_lang = frame.args[3];
    while s_lang ~= nil do
      langs[n_index] = tostring(s_lang);
      n_index = n_index + 1;
      s_lang = frame.args[n_index];
    end;
    sitelink = wd.get_sitelink_by_lang(entity, s_code, langs);
  end;
  if sitelink == nil then
    return nil;
  else
    return wd.map_sitelink_to_prefix(sitelink.site) .. sitelink.title;
  end;
end;
--
-- s_suffix - sitelink проекта ("wiki", "wikisource", "wikiwikiquote", "wikivoyage" или "wikinews")
function wd.get_multilingual_sitelink(entity, s_suffix, lang_properties)
  if (entity == nil) or (entity["sitelinks"] == nil) then
    return nil;
  end;
  local sitelink = entity.sitelinks["ru" .. s_suffix];
  if sitelink ~= nil then
    return wd.map_sitelink_to_prefix(sitelink.site) .. sitelink.title;
  elseif lang_properties == nil then
    return nil;
  end;
  -- собираем языки в langs
  local langs = {Q7737="ru"};   -- список языков, sitelink'и для которых мы уже проверили
  local lang_cache = nil;          -- кэш языков из Модуль:Wikidata:Dictionary/P424
  for key1, s_lang_property in pairs(lang_properties) do
    --mw.log("look at " .. s_lang_property);
    for key2, statement in pairs(entity:getBestStatements(s_lang_property)) do
      local s_lang_qid = wd.get_item_qid(statement);
      --mw.log("  " .. s_lang_qid);
      if (s_lang_qid ~= nil) and langs[s_lang_qid] == nil then
        if lang_cache == nil then      -- кэш языков загружаем только в первый раз
          lang_cache = mw.loadData('Модуль:Wikidata:Dictionary/P424');
        end;
        local l = lang_cache[s_lang_qid];
        if l == nil then
          mw.log("В Модуль:Wikidata:Dictionary/P424 отсутствует язык " .. s_lang_qid);
        else 
          for key3, s_lang in pairs(l) do
            sitelink = entity.sitelinks[s_lang..s_suffix];
            if sitelink ~= nil then
              return wd.map_sitelink_to_prefix(sitelink.site) .. sitelink.title;
            end;
            langs[s_lang_qid] = s_lang;
          end;
        end;
      end;
    end;
  end;
  return nil;
end;
--[[
-- {{#invoke:Sandbox|test_get_multilingual_sitelink|Q18090050|wikisource}}
function s.test_get_multilingual_sitelink (frame)
  local s_qid     = tostring(frame.args[1]);
  local s_suffix  = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_qid);
  local s_sitelink = s.get_multilingual_sitelink(entity, s_suffix, {"P1412","P103"});
  if s_sitelink == nil then
    return "nil";
  else
    return s_sitelink;
  end;
end;
]]
--
----------------------------------------------------------------------------------------------------------
-- Функция для Шаблон:WD property
-- Возвращает строку вида: [[:d:Property:Pxxx|<метка> (Pxxx)]]
--  {{#invoke:WD|format_property|id|lang}}
--
-- Параметры:
--  id — идентификатор свойства Викиданных (Pxxx)
--  lang — двухбуквенный код языка, на котором отображается метка (ru, en, de, etc)
--
-- Если метки на этом языке нет, то возвращается метка на английском (она почти всегда есть)
--
-- Примеры:
--  {{#invoke:WD|format_property|P569|ru}}  → [[:d:Property:P569|дата рождения (P569)]]
--  {{#invoke:WD|format_property|P569|en}}  → [[:d:Property:P569|date of birth (P569)]]
--  {{#invoke:WD|format_property|P569|de}}  → [[:d:Property:P569|Geburtsdatum (P569)]]
--  {{#invoke:WD|format_property|P569|la}}  → [[:d:Property:P569|natus (P569)]]
--
--  {{#invoke:WD|format_property|P97|ru}}  → [[:d:Property:P97|титул (P97)]]
--  {{#invoke:WD|format_property|P97|en}}  → [[:d:Property:P569|noble title (P97)]]
--  {{#invoke:WD|format_property|P97|la}}  → [[:d:Property:P569|noble title (P97)]] (так как метки на латыни нет)
--
--  {{#invoke:WD|format_property|P999999|ru}}  → ошибка  (несуществующее свойство)
--
function wd.format_property (frame)
  local s_property_id = tostring(frame.args[1]);
  local s_lang = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_property_id);
  if (entity == nil) or not wd.is_property(entity) then
    error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_property_id));
  end;
  return "[[:d:Property:" .. entity.id .. "|" .. wd.get_label(entity, s_lang, MSG_NO_LABEL) .. " (" .. entity.id .. ")]]";
end;
--
----------------------------------------------------------------------------------------------------------
-- Функция для Шаблон:WD item
-- Возвращает строку вида: [[:d:Qxxx|<метка> (Qxxx)]]
--  {{#invoke:WD|format_item|id|lang}}
--
-- Параметры:
--  id — идентификатор элемента Викиданных (Qxxx)
--  lang — двухбуквенный код языка, на котором отображается метка (ru, en, de, etc)
--
-- Если метки на этом языке нет, то возвращается метка на английском
--
-- Примеры:
--  {{#invoke:WD|format_item|Q2|ru}} → [[:d:Q2|Земля (Q2)]]
--  {{#invoke:WD|format_item|Q2|en}} → [[:d:Q2|Earth (Q2)]]
--  {{#invoke:WD|format_item|Q2|de}} → [[:d:Q2|Erde (Q2)]]
--  {{#invoke:WD|format_item|Q2|la}} → [[:d:Q2|Tellus (Q2)]]
--
--  {{#invoke:WD|format_item|Q6|ru}} → ошибка (несуществующий элемент)
--  {{#invoke:WD|format_item|Q8258093|ru}} → [[:d:Q6305566|Category:Aquitanians (Q6305566)]] (перенаправление Q8258093 → Q6305566)
--
function wd.format_item (frame)
  local s_item_id = tostring(frame.args[1]);
  local s_lang = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_item_id);
  if (entity == nil) or not wd.is_item(entity) then
    error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_item_id));
  end;
  return "[[:d:" .. entity.id .. "|" .. wd.get_label(entity, s_lang, MSG_NO_LABEL) .. " (" .. entity.id .. ")]]";
end;
--
----------------------------------------------------------------------------------------------------------
-- Сервисная функция, позволяющая преобразовать таблицу LUA в её текстовое представление
--
function wd.table_to_string(t, s_indent)
  local s_result = "{";
  -- флажок, чтобы не добавлять запятую после последнего элемента, и чтобы при пустой таблице возвращалось "{" .. s_indent .. "}"
  local b_first = true;
  for key, value in pairs(t) do
    if b_first then
      s_result = s_result .. "<br/>";  -- перед первым элементом добавляем перевод строки
      b_first = false;                 -- и сбрасываем флажок
    else
      s_result = s_result .. ",<br/>";  -- перед всеми последующими добавляем запятую и перевод строки
    end;
    local s_str = "";
    if value == nil then
      s_str = "nil";
    elseif type(value) == "table" then
      s_str = wd.table_to_string(value, s_indent .. "&nbsp;&nbsp;");
    elseif type(value) == "string" then
      s_str = "\"" .. value .. "\"";
    else -- type(value) == "number", "boolean" или "function"
      s_str = tostring(value);
    end;
    if (type(key) == "number") or (type(key) == "boolean") then
      s_result = s_result .. s_indent .. tostring(key) .. ": " .. s_str;
    else
      s_result = s_result .. s_indent .. "\"" .. tostring(key) .. "\": " .. s_str;
    end;
  end;
  if not b_first then
    s_result = s_result .. "<br/>";  -- если был хотя бы один элемент, добавляем перевод строки
  end;
  return s_result .. s_indent .. "}";
end;
--
----------------------------------------------------------------------------------------------------------
-- Отладочная функция, позволяющая показать элемент или свойство Тептар данных, возвращаемое функцией mw.wikibase.getEntityObject()
--
-- Примеры:
-- {{#invoke:WD|dump_entity|Q3207456}}
-- {{#invoke:WD|dump_entity|P31}}
--
function wd.dump_entity(frame)
  local s_id = tostring(frame.args[1]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if entity == nil then
    if mw.ustring.match(s_id, "[Qq]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_id));
    elseif mw.ustring.match(s_id, "[Pp]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_id));
    else
      error(mw.ustring.format(ERRMSG_ENTITY_NOT_FOUND, s_id));
    end;
  end;
  return wd.table_to_string(entity, "");
end;
--
-- {{#invoke:WD|dump_sitelinks|Q359}}
-- {{#invoke:WD|dump_sitelinks|Q9301454}}
--
function wd.dump_sitelinks(frame)
  local s_id = tostring(frame.args[1]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if (entity == nil) or not wd.is_item(entity) then
    error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_item_id));
  end;
  if entity["sitelinks"] == nil then
    return "nil"
  else
    return wd.table_to_string(entity.sitelinks, "");
  end;
end;
--
--[[
{{#invoke:WD|dump_property|Q44403|P20}} (item, одно значение)
{{#invoke:WD|dump_property|Q15920521|P19}} (wikibase-entityid)
{{#invoke:WD|dump_property|Q44403|P569}} (time)

{{#invoke:WD|dump_property|Q15920521|P1476}} (monolingualtext)
{{#invoke:WD|dump_property|Q359|P856}} (url)

Примеры значений переменной value (вязто с помощью https://www.wikidata.org/wiki/Special:EntityData/Q15920521.json):
[{"id":"Q15920521$f7c04336-4b68-8307-c98c-569412466eaa",
  "mainsnak":{"snaktype":"value",
              "property":"P1476",
              "datatype":"monolingualtext",
              "datavalue":{"value":{"text":"Ночные мысли","language":"ru"},"type":"monolingualtext"}},
  "type":"statement",
  "rank":"normal"}]

[{"id":"Q359$36814403-433c-591b-eaff-22a38472a46b",
  "mainsnak":{"snaktype":"value",
              "property":"P856",
              "datatype":"url",
              "datavalue":{"value":"https://wikileaks.org/","type":"string"}},
              "type":"statement",
              "rank":"normal"}]
]]
function wd.dump_statements(frame)
  local s_id = tostring(frame.args[1]);
  local s_property_id = tostring(frame.args[2]);
  local entity = mw.wikibase.getEntityObject(s_id);
  if entity == nil then
    if mw.ustring.match(s_id, "[Qq]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_ITEM_NOT_FOUND, s_id));
    elseif mw.ustring.match(s_id, "[Pp]%d+") ~= nil then
      error(mw.ustring.format(ERRMSG_PROPERTY_NOT_FOUND, s_id));
    else
      error(mw.ustring.format(ERRMSG_ENTITY_NOT_FOUND, s_id));
    end;
  end;
  local claim = nil;
  if entity.claims ~= nil then
    claim = entity.claims[s_property_id];
  end;
  if claim == nil then
    error(mw.ustring.format(ERRMSG_CLAIM_NOT_FOUND, s_id, s_property_id));
  end;
  return wd.table_to_string(claim, "");
--[[
  local s_result = ""
  for key, value in pairs(claim) do
    local snak = value.mainsnak;
    s_result = s_result .. "[" .. key .. "]: id = " .. value.id .. ", type = " .. value.type .. ", rank = " .. value.rank .. ", snaktype = " .. snak.snaktype .. ", property = " .. snak.property
    if snak.snaktype == "value" then
      s_result = s_result .. ", datatype = " .. snak.datavalue.type
      if snak.datavalue.type == "wikibase-entityid" then
          s_result = s_result .. ", value = Q".. tostring(snak.datavalue.value["numeric-id"])
      elseif snak.datavalue.type == "string" then
          s_result = s_result .. ", value = '" .. snak.datavalue.value .."'"
      elseif snak.datavalue.type == "monolingualtext" then
          s_result = s_result .. ", language = '" .. snak.datavalue.value.language .. "', value = '" .. snak.datavalue.value.text .."'"
      elseif snak.datavalue.type == "url" then
          s_result = s_result .. ", value = '" .. snak.datavalue.value .."'"
      elseif snak.datavalue.type == "time" then
          s_result = s_result .. ", value = " .. snak.datavalue.value.time .. " (precision = " .. tostring(snak.datavalue.value.precision) .. ", before = " .. tostring(snak.datavalue.value.before) .. ",  after = " .. tostring(snak.datavalue.value.after) .. ", timezone = " .. tostring(snak.datavalue.value.timezone) .. ", calendarmodel = " .. tostring(snak.datavalue.value.calendarmodel) .. ")"
      end
    end
    s_result = s_result .. "<br/>"
  end;
  return s_result;
]]
end;

return wd;