Модуль:WD (Bk;rl,&WD)

Перейти к навигации Перейти к поиску
Документация

Назначение

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

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

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}} → дата рождения
  • {{#invoke:WD|label|P569|en}} → date of birth
  • {{#invoke:WD|label|P569|de}} → Geburtsdatum
  • {{#invoke:WD|label|P569|la}} → dies natalis
  • {{#invoke:WD|label|P97|ru}} → титул
  • {{#invoke:WD|label|P97|en}} → noble title
  • {{#invoke:WD|label|P97|la}} (нет метки на латыни) → noble title

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

  • {{#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|Q8258093|ru}} (перенаправление Q8258093 → Q6305566) → Category:Aquitani

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

  • {{#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}} → день, месяц, год, в который субъект был рождён
  • {{#invoke:WD|description|P569|en}} → date on which the subject was born
  • {{#invoke:WD|description|P569|de}} → Datum, an dem eine Person geboren wurde
  • {{#invoke:WD|description|P97|ru}} → дворянский титул персоны
  • {{#invoke:WD|description|P97|en}} → titles held by the person
  • {{#invoke:WD|description|P97|la}} (нет описания на латыни) → titles held by the person

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

  • {{#invoke:WD|description|Q2|ru}} → третья от Солнца планета о солнечное системе
  • {{#invoke:WD|description|Q2|en}} → third planet from the Sun in the Solar System
  • {{#invoke:WD|description|Q2|de}} → dritter Planet von der Sonne aus im Sonnensystem
  • {{#invoke:WD|description|Q2|la}} (нет описания на латыни) → tertius planeta a Sole in systemate solari
  • {{#invoke:WD|description|Q8258093|ru}} (перенаправление Q8258093 → Q6305566) → категория в проекте Викимедиа

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

  • {{#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}} → wikibase-item
  • {{#invoke:WD|datatype|P1687}} → wikibase-property
  • {{#invoke:WD|datatype|P304}} → string
  • {{#invoke:WD|datatype|P1476}} → monolingualtext
  • {{#invoke:WD|datatype|P18}} → commonsMedia
  • {{#invoke:WD|datatype|P854}} → url
  • {{#invoke:WD|datatype|P569}} → time
  • {{#invoke:WD|datatype|P625}} → globe-coordinate
  • {{#invoke:WD|datatype|P2067}} → quantity

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

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

dump_entity()

Описание
Отладочная функция, позволяющая показать значение в формате JSON, возвращаемое функцией mw.wikibase.getEntity() для указанного элемента или свойства Викиданных.
Использование
{{#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}} {
"ruwikisource": {
  "site": "ruwikisource",
  "title": "Ночные мысли (Гейне; Михайлов)",
  "badges": {    }
  }
}
{{#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}} {
1: {
  "mainsnak": {
    "snaktype": "value",
    "property": "P1696",
    "datavalue": {
      "value": {
        "id": "P361",
        "numeric-id": 361,
        "entity-type": "property"
        },
      "type": "wikibase-entityid"
      },
    "datatype": "wikibase-property"
    },
  "type": "statement",
  "id": "P527$a8ab8c55-4864-573a-67d0-613917797d1d",
  "rank": "normal"
  }
}
{{#invoke:WD|dump_statements|Q15920521|P1476}} {
1: {
  "mainsnak": {
    "snaktype": "value",
    "property": "P1476",
    "datavalue": {
      "value": {
        "language": "ru",
        "text": "Ночные мысли"
        },
      "type": "monolingualtext"
      },
    "datatype": "monolingualtext"
    },
  "type": "statement",
  "id": "Q15920521$f7c04336-4b68-8307-c98c-569412466eaa",
  "rank": "normal"
  }
}
{{#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()

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.getEntity(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.getEntity(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.getEntity(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.getEntity(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.getEntity(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.getEntity(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.getEntity(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.getEntity()
--
-- Примеры:
-- {{#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.getEntity(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.getEntity(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.getEntity(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;