Модуль: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}} (нет описания на латыни) → third planet from the Sun in the Solar System
  • {{#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.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}} {
"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()[править]

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;