Module:Wikidata label: Difference between revisions
Content deleted Content added
GVarnum-WMF (talk | contribs) m 1 revision imported from meta:Module:Wikidata_label |
GVarnum-WMF (talk | contribs) m 1 revision imported from meta:Module:Wikidata_label |
||
(One intermediate revision by one other user not shown) | |||
Line 1: | Line 1: | ||
--[[ |
--[[ |
||
__ __ _ _ __ ___ _ _ _ _ _ _ _ |
__ __ _ _ __ ___ _ _ _ _ _ _ _ |
||
| \/ | ___ __| |_ _| | ___ \ \ / (_) | _(_) __| | __ _| |_ __ _ | | __ _| |__ ___| | |
| \/ | ___ __| |_ _| | ___ \ \ / (_) | _(_) __| | __ _| |_ __ _ | | __ _| |__ ___| | |
||
| |\/| |/ _ \ / _` | | | | |/ _ (_) \ /\ / /| | |/ / |/ _` |/ _` | __/ _` | | |/ _` | '_ \ / _ \ | |
| |\/| |/ _ \ / _` | | | | |/ _ (_) \ /\ / /| | |/ / |/ _` |/ _` | __/ _` | | |/ _` | '_ \ / _ \ | |
||
| | | | (_) | (_| | |_| | | __/_ \ V V / | | <| | (_| | (_| | || (_| | | | (_| | |_) | __/ | |
| | | | (_) | (_| | |_| | | __/_ \ V V / | | <| | (_| | (_| | || (_| | | | (_| | |_) | __/ | |
||
|_| |_|\___/ \__,_|\__,_|_|\___(_) \_/\_/ |_|_|\_\_|\__,_|\__,_|\__\__,_| |_|\__,_|_.__/ \___|_| |
|_| |_|\___/ \__,_|\__,_|_|\___(_) \_/\_/ |_|_|\_\_|\__,_|\__,_|\__\__,_| |_|\__,_|_.__/ \___|_| |
||
This module is intended to be the engine behind "Template:Label". |
This module is intended to be the engine behind "Template:Label". |
||
This module was copied from Commons please ask for changes there. |
|||
Please do not modify this code without applying the changes first at "Module:Wikidata label/sandbox" and testing |
Please do not modify this code without applying the changes first at "Module:Wikidata label/sandbox" and testing |
||
at "Module:Wikidata label/testcases". |
at "Module:Wikidata label/testcases". |
||
Authors and maintainers: |
Authors and maintainers: |
||
* User:Jarekt - original version |
* User:Jarekt - original version |
||
Dependencies: |
|||
* Module:Yesno - used only if "show_id" parameter present |
|||
]] |
]] |
||
require('strict') -- used for debugging purposes as it detects cases of unintended global variables |
|||
--============================================= |
|||
--=== Internal functions ====================== |
|||
--============================================= |
|||
--------------------------------------------------------------------------- |
|||
-- Normalize input arguments by converting them all to lower case and |
|||
-- replacing space with "_" in the argument name. Also empty strings are |
|||
-- converted to nils. Arguments are collected from arguments passed to the |
|||
-- module and if missing from the template that calls the module |
|||
local function getArgs(frame) |
|||
local function normalize_input_args(input_args, output_args) |
|||
for name, value in pairs( input_args ) do |
|||
value = mw.text.trim(value) -- trim whitespaces from the beggining and the end of the string |
|||
if value ~= '' then -- nuke empty strings |
|||
if type(name)=='string' then |
|||
name = string.gsub( string.lower(name), ' ', '_') |
|||
end |
|||
output_args[name] = value |
|||
end |
|||
end |
|||
return output_args |
|||
end |
|||
local args = {} |
|||
args = normalize_input_args(frame:getParent().args, args) |
|||
args = normalize_input_args(frame.args, args) |
|||
return args |
|||
end |
|||
--------------------------------------------------------------------------- |
|||
-- Function allowing for consistent treatment of boolean-like wikitext input. |
|||
-- It works similarly to Module:Yesno but does not assume val is a string |
|||
local function yesno(val, default) |
|||
if type(val) == 'boolean' then |
|||
return val |
|||
elseif type(val) == 'number' then |
|||
if val == 1 then |
|||
return true |
|||
elseif val == 0 then |
|||
return false |
|||
end |
|||
elseif type(val) == 'string' then |
|||
val = mw.ustring.lower(val) -- put in lower case |
|||
if val == 'no' or val == 'n' or val == 'false' or val == '0' then |
|||
return false |
|||
elseif val == 'yes' or val == 'y' or val == 'true' or val == '1' then |
|||
return true |
|||
end |
|||
end |
|||
return default |
|||
end |
|||
------------------------------------------------------------------------- |
|||
-- get message in a given language |
|||
-- INPUTS: |
|||
-- * msg - name of a message. For it to work [[MediaWiki:msg]] page need to be set up |
|||
-- * lang - translate message to language "lang" |
|||
-- * default - string to return in case this module is moved to a project where this message is not set |
|||
-- OUTPUT: |
|||
-- * translated message |
|||
local function getMessage(msg, lang, default) |
|||
msg = mw.message.new(msg):inLanguage(lang):plain() |
|||
return (msg == nil and default) or msg |
|||
end |
|||
--------------------------------------------------------------------------- |
|||
-- use different sitelink call depending if you already have an entity or not |
-- use different sitelink call depending if you already have an entity or not |
||
-- INPUTS: |
|||
-- * item and entity - entity id and entity: if full entity already uploded than use that |
|||
-- otherwise use entity id to look up sitelink |
|||
-- * lang - language of the project |
|||
-- OUTPUT: |
|||
-- * sitelink |
|||
local function getSitelink(item, entity, lang) |
local function getSitelink(item, entity, lang) |
||
if entity then -- if we have entity |
if entity and entity.getSitelink then -- if we have entity then use it |
||
return entity:getSitelink(lang .. 'wiki') |
return entity:getSitelink(lang .. 'wiki') |
||
else -- if no entity |
else -- if no entity then use different function |
||
return mw.wikibase. |
return mw.wikibase.getSitelink(item, lang .. 'wiki') |
||
end |
end |
||
end |
end |
||
--------------------------------------------------------------------------- |
|||
-- use different sitelink call depending if you already have an entity or not |
|||
-- INPUTS: |
|||
-- * item and entity - entity id and entity: if full entity already uploded than use that |
|||
-- otherwise use entity id to look up sitelink |
|||
-- * prop - property for which to return the best statment |
|||
-- OUTPUT: |
|||
-- * value of the best statment (only from the first one) |
|||
local function getBestStatementsValue(item, entity, prop) |
|||
local statments |
|||
if entity then |
|||
statments = entity:getBestStatements(prop) |
|||
else |
|||
statments = mw.wikibase.getBestStatements(item, prop) |
|||
end |
|||
for _, statment in ipairs(statments) do |
|||
if statment and statment.mainsnak.datavalue.value then |
|||
return statment.mainsnak.datavalue.value |
|||
end |
|||
end |
|||
end |
|||
--------------------------------------------------------------------------- |
|||
-- change capitalization of the label |
|||
-- INPUTS: |
|||
-- * label - label string |
|||
-- * capitalization - capitalization to be applied: allowed values are "tc", "lc", |
|||
-- "uc", "lcfirst", and "ucfirst". Any other value will return original string |
|||
-- * lang - language of the label |
|||
-- OUTPUT: |
|||
-- * value of the best statment (only from the first one) |
|||
local function apply_capitalization(label, capitalization, lang) |
|||
capitalization = string.lower(capitalization or 'none') |
|||
if capitalization == 'none' then |
|||
return label |
|||
elseif capitalization == 'uc' then |
|||
return mw.language.new(lang):uc(label) |
|||
elseif capitalization == 'lc' then |
|||
return mw.language.new(lang):lc(label) |
|||
elseif capitalization == 'tc' then -- title case |
|||
local new_label = {} |
|||
for _, word in ipairs(mw.text.split(label, ' ')) do |
|||
table.insert(new_label, mw.language.new(lang):ucfirst(word)) |
|||
end |
|||
return table.concat(new_label, ' ') |
|||
elseif capitalization == 'ucfirst' then |
|||
return mw.language.new(lang):ucfirst(label) |
|||
elseif capitalization == 'lcfirst' then |
|||
return mw.language.new(lang):lcfirst(label) |
|||
end |
|||
return label |
|||
end |
|||
--[[------------------------------------------------------------------------- |
|||
get link based on user preference |
|||
INPUTS: |
|||
* link_type - can be : |
|||
* "wikidata" - link to wikidata |
|||
* "wikipedia" - link to wikipedia (language dependent) |
|||
* "wikidata talk" - link to wikidata talk page |
|||
* "commons" - link to commons (try sitelink then commons category then commons gallery) |
|||
* "commonscat" - link to commons (try commons category then commons gallery) |
|||
* "-" - means no link |
|||
* item - entity ID (always provided) |
|||
* entity - whole entity. It can be nil if whole entity is not loaded |
|||
* langList - language fallback list for preferred language (required) |
|||
OUTPUT: |
|||
* link - link to the wikimedia page |
|||
]] |
|||
local function getLink(link_type, item, entity, langList) |
|||
local link, eLink |
|||
link_type = mw.ustring.lower(link_type or '') |
|||
local item_type = mw.ustring.sub(item, 1, 1) -- first letter prefix of item entity ID: 'Q', 'P' or 'M' |
|||
if item_type == 'M' then |
|||
eLink='c:Special:EntityPage/'..item |
|||
elseif item_type == 'Q' then |
|||
eLink='d:'..item -- wikibase entity page link |
|||
elseif item_type == 'P' then |
|||
eLink='d:Property:'..item -- wikibase entity page link |
|||
else |
|||
eLink='d:Special:EntityPage/'..item |
|||
end |
|||
if link_type == '-' then -- allow different link formats |
|||
link = '' -- no link |
|||
elseif link_type == 'wikidata' or item_type == 'M' then |
|||
link = eLink -- link to wikibase entity page |
|||
elseif link_type == 'wikidata talk' and item_type == 'P' then |
|||
link = 'd:Property talk:'.. item -- link to wikidata property talk page |
|||
elseif link_type == 'wikidata talk' then |
|||
link = 'd:Talk:'..item -- link to wikidata talk page |
|||
elseif link_type == 'commons' or link_type == 'commonscat' then |
|||
--[[ |
|||
When link_type == 'commons' we try the following links (in specified order): |
|||
1) commons sitelink |
|||
2) P373 "Commons Category" claims |
|||
3) P935 "Commons Gallery" claims |
|||
Since most items have a commons sitelink we never have to look for claims |
|||
When link_type == 'commonscat' we try to maximize chances of commons link being a category, so we |
|||
try the following links (in specified order): |
|||
1) commons sitelink, which is kept if it points to a category |
|||
2) P373 "Commons Category" claims |
|||
3) commons sitelink (which does not point to a category) |
|||
4) P935 "Commons Gallery" claims |
|||
Since most pages have a commons sitelink we never have to look for claims |
|||
]] |
|||
local sLink = getSitelink(item, entity, 'commons') -- look for sitelink to commons |
|||
if sLink then |
|||
sLink = 'c:'..sLink |
|||
if (link_type == 'commons') or (link_type == 'commonscat' and mw.ustring.find(sLink, 'Category:')) then |
|||
link = sLink |
|||
end |
|||
end |
|||
if not link then -- try linking to P373 "Commons Category" |
|||
local cat = getBestStatementsValue(item, entity, 'P373') |
|||
link = (cat ~= nil and 'c:Category:' .. cat) or nil |
|||
end |
|||
link = link or sLink |
|||
if not link then -- try linking to P935 "Commons Gallery" |
|||
link = getBestStatementsValue(item, entity, 'P935') |
|||
end |
|||
end |
|||
if not link then -- apply default "Wikipedia" link type |
|||
for _, language in ipairs(langList) do |
|||
local sitelink = getSitelink(item, entity, language) |
|||
if sitelink then |
|||
link = 'w:'.. language ..':'.. sitelink |
|||
break |
|||
end |
|||
end |
|||
end |
|||
return link or eLink -- no wiki sitelink, so link to wikidata |
|||
end |
|||
--============================================= |
|||
--=== External functions ====================== |
|||
--============================================= |
|||
local p = {} |
local p = {} |
||
--====================================================================== |
|||
--=== API functions for use from other Scribunto modules =============== |
|||
--====================================================================== |
|||
--[[ |
--[[ |
||
Line 36: | Line 247: | ||
Inputs: |
Inputs: |
||
1: item - wikidata's item's q- |
1: item - wikidata's item's q-id or entity class |
||
2: lang - desired language of the label |
2: lang - desired language of the label |
||
3: link_type - link style. Possible values: "wikipedia", " |
3: link_type - link style. Possible values (case-insensitive): "wikipedia", "wikidata", "Commons", or "-" (no link) |
||
4: capitalization - can be "uc" (upper case), "lc" (lower case), "ucfirst" (upper case for the first letter), |
4: capitalization - can be "uc" (upper case), "lc" (lower case), "ucfirst" (upper case for the first letter), |
||
"lcfirst" (lower case for the first letter) |
"lcfirst" (lower case for the first letter), or 'none' (default) |
||
Error Handling: |
Error Handling: |
||
Bad q- |
Bad q-id will result in displayed error |
||
]] |
]] |
||
function p._getLabel(item, lang, link_type, capitalization, show_id) |
function p._getLabel(item, lang, link_type, capitalization, show_id) |
||
local entity, s, link, label, language |
local entity, s, link, label, language, desc |
||
-- clean up the input parameters |
-- clean up the input parameters |
||
if type(item)~='string' then -- "item" is not a q- |
if type(item) ~= 'string' then -- "item" is not a q-id |
||
entity = item -- "item" must be the entity |
entity = item -- "item" must be the entity |
||
item = entity.id -- look-up q- |
item = entity.id -- look-up q-id |
||
elseif tonumber(item) then -- if it is just the number |
elseif tonumber(item) then -- if it is just the number then add "Q" in front |
||
item = 'Q'..item |
item = 'Q'..item |
||
end |
end |
||
item = |
item = mw.ustring.gsub(mw.ustring.upper(item), 'PROPERTY:P', 'P') -- make all the properties the same and capitalize |
||
if not lang then |
|||
label, lang = mw.wikibase.getLabelWithLang(item) |
|||
end |
|||
if not lang then -- if still no language |
|||
lang = mw.getCurrentFrame():callParserFunction("int","lang") -- get user's chosen language |
|||
label = nil |
|||
end |
|||
-- build language fallback list |
-- build language fallback list |
||
lang = |
lang = mw.ustring.lower(lang) |
||
local langList = mw.language.getFallbacksFor(lang) |
local langList = mw.language.getFallbacksFor(lang) |
||
table.insert(langList, 1, lang) |
table.insert(langList, 1, lang) |
||
-- get label (visible part of the link) |
-- get label (visible part of the link) |
||
if not label then |
|||
for _, language in ipairs(langList) do -- loop over language fallback list looking for label in the specific language |
|||
for _, language in ipairs(langList) do -- loop over language fallback list looking for label in the specific language |
|||
if entity then |
|||
label = entity:getLabel(language) |
if entity then |
||
label = entity:getLabel(language) |
|||
else |
else |
||
label = mw.wikibase.getLabelByLang(item, language) |
label = mw.wikibase.getLabelByLang(item, language) |
||
end |
|||
if label then break end -- label found and we are done |
|||
end |
end |
||
if label then break end -- label found and we are done |
|||
end |
end |
||
if |
if label then -- wikitext-escape the label if we have one |
||
label = mw.text.nowiki(label) |
|||
end |
|||
if not label then -- no labels found, so just show the q-id |
|||
label = item |
label = item |
||
elseif show_id then -- add id |
elseif show_id then -- add id |
||
local yesno = require('Module:Yesno') |
|||
show_id = yesno(show_id,false) |
show_id = yesno(show_id,false) |
||
if show_id then |
if show_id then |
||
local wordsep = getMessage('Word-separator', lang, ' ') |
|||
local id = mw.getCurrentFrame():preprocess( "{{int:parentheses|" .. item .."}}") |
|||
local |
local id = mw.message.new('parentheses', item):inLanguage(lang):plain() |
||
id = (id~=nil and id) or ('('..item..')') -- in case this module is moved to a project where {{int:parenthesis}} is not set |
|||
label = label .. wordsep .. "<small>" .. id .. "</small>" |
label = label .. wordsep .. "<small>" .. id .. "</small>" |
||
end |
end |
||
end |
end |
||
label = apply_capitalization(label, capitalization, lang) |
|||
-- look for description |
|||
-- change capitalization of the label |
|||
if entity and entity.descriptions and lang then |
|||
if capitalization=='ucfirst' then |
|||
for _, language in ipairs(langList) do |
|||
if entity.descriptions[language] then |
|||
elseif capitalization=='lcfirst' then |
|||
desc = entity.descriptions[language].value |
|||
break |
|||
elseif capitalization=='uc' then |
|||
label = mw.language.new(lang):uc(label) |
|||
elseif capitalization=='lc' then |
|||
label = mw.language.new(lang):lc(label) |
|||
end |
|||
-- create URL part of the link |
|||
link_type = string.lower(link_type or '') |
|||
local dLink = 'd:'..item; -- create fallback wikidata link |
|||
if string.sub(item, 1, 1) == 'P' then |
|||
dLink = 'd:Property:'.. item |
|||
end |
|||
if link_type=='-' then -- allow different link formats |
|||
link = '' -- no link |
|||
elseif link_type=='wikidata' then |
|||
link = dLink -- link to wikidata |
|||
elseif link_type=='wikidata talk' and string.sub(item, 1, 1)=='P' then |
|||
link = 'd:Property talk:'.. item -- link to wikidata property talk page |
|||
elseif link_type=='wikidata talk' then |
|||
link = 'd:Talk:'..item -- link to wikidata talk page |
|||
elseif link_type=='commons' or link_type=='commonscat' then |
|||
-- For link_type=='commons' we try the following links (in that order): |
|||
-- 1) sitelink to commons |
|||
-- 2) "Commons Category" P373 property |
|||
-- 3) "Commons Gallery" P935 property |
|||
-- Since most pages have a sitelink to commons we never have to call expensive mw.wikibase.getEntity |
|||
-- For link_type=='commonscat' we try to maximize chances of commons link beeing a category, so we |
|||
-- try the following links (in that order): |
|||
-- 1) sitelink to commons, which is kept if it points to a category |
|||
-- 2) "Commons Category" P373 property |
|||
-- 3) sitelink to commons (which does not point to a category) |
|||
-- 4) "Commons Gallery" P935 property |
|||
-- Since most pages have a sitelink to commons we never have to call expensive mw.wikibase.getEntity |
|||
local sLink = getSitelink(item, entity, 'commons') -- look for sitelink to commons |
|||
if sLink then |
|||
sLink = 'c:'..sLink |
|||
if (link_type=='commons') or (link_type=='commonscat' and string.find( sLink, 'Category:')) then |
|||
link = sLink |
|||
end |
|||
end |
|||
if not link then -- try linking to P373 category |
|||
-- this is potentially memory expensive operation |
|||
entity = entity or mw.wikibase.getEntity(item); |
|||
assert(entity, "Item ID " .. item .. " is not valid") |
|||
s = entity:getBestStatements( 'P373' ) |
|||
if s[1] and s[1].mainsnak.datavalue.value then |
|||
link = 'c:Category:' .. s[1].mainsnak.datavalue.value |
|||
end |
|||
end |
|||
link = link or sLink |
|||
if not link then -- try linking to P935 gallery |
|||
-- there is no need for mw.wikibase.getEntity(item) call since at this point it was already loded |
|||
s = entity:getBestStatements( 'P935' ) |
|||
if s[1] and s[1].mainsnak.datavalue.value then |
|||
link = s[1].mainsnak.datavalue.value |
|||
end |
end |
||
end |
end |
||
else |
|||
desc = mw.wikibase.getDescription(item) |
|||
end |
end |
||
if desc and link_type ~= '-' then -- wikitext-escape the description if we have one |
|||
if not link then-- apply default "Wikipedia" link type |
|||
desc = mw.text.nowiki(desc) -- add description as hover text |
|||
for _, language in ipairs(langList) do |
|||
label = '<span title="' .. desc .. '">' .. label .. '</span>' |
|||
local sitelink = getSitelink(item, entity, language) |
|||
if sitelink then |
|||
link = mw.ustring.format('w:%s:%s', language, sitelink) |
|||
break |
|||
end |
|||
end |
|||
end |
end |
||
link = link or dLink -- no wiki sitelink, so link to wikidata |
|||
-- return the results |
-- return the results |
||
if |
if link_type == '-' then |
||
return |
return label -- return just the label |
||
else |
else |
||
link = getLink(link_type, item, entity, langList) |
|||
return label -- return just a label |
|||
return '[[' .. link .. '|' .. label .. ']]' -- return link |
|||
end |
end |
||
end |
end |
||
--[[------------------------------------------------------------------------------- |
|||
--[[ |
|||
_sitelinks |
|||
getLabel |
|||
This function returns a label translated to desired language, created based on wikidata |
|||
This function returns a table of sitelinks for a single project organized by language |
|||
Usage: |
|||
{{#invoke:Wikidata label|getLabel|item=Q...|lang=..|link_style=..|capitalization=..}} |
|||
Inputs: |
|||
Parameters |
|||
1: wikidata's item's q- |
1: item - wikidata's item's q-id or entity class |
||
2: project - (case-insensitive) one of: "wikipedia", "wikisource", "wikiquote", "wikibooks", "wikinews", |
|||
2: language (optional; default {{int:lang}} ) |
|||
"wikiversity", "wikivoyage", "wiktionary", "commons", "mediawiki", "wikispecies", "wikidata", etc. |
|||
3: link_style: "wikipedia" (default), "Wikidata", "Commons", or "-" (no link) |
|||
4: capitalization - can be "uc", "lc", "ucfirst", "lcfirst" |
|||
Output: |
|||
Error Handling: |
|||
Table of sitelinks with language fields |
|||
Bad q-code will result in displayed error |
|||
Output: |
|||
Table of sitelinks with language fields |
|||
See also |
|||
* [https://foundation.wikimedia.org/wiki/Special:SiteMatrix] for the full list of supported interwikis. |
|||
* [https://dumps.wikimedia.org/backup-index.html] for the full list of sitecodes (used in database dumps). |
|||
]] |
]] |
||
function p. |
function p._sitelinks(item, project) |
||
local |
local entity, sitelink |
||
-- get entity |
|||
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then |
|||
if type(item) == 'string' then -- "item" is a q-id |
|||
args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language |
|||
entity = mw.wikibase.getEntity(item) |
|||
else |
|||
entity = item -- "item" is the entity |
|||
end |
end |
||
if (not args.link) or (mw.text.trim(args.link) == "") then |
|||
-- convert from english project name to proproject code |
|||
args.link = "wikipedia" |
|||
local projLUT = { |
|||
wikipedia = 'wiki', commons = 'commonswiki', |
|||
foundation = 'foundationwiki', mediawiki = 'mediawikiwiki', |
|||
wikispecies = 'specieswiki', wikidata = 'wikidatawiki', |
|||
incubator = 'incubatorwiki', oldwikisource = 'sourceswiki', |
|||
} |
|||
local langLUT = { |
|||
-- These are not language codes before the 'wiki' or 'wikiversity' suffix in a sitecode: |
|||
foundation = '~', commons = '~', -- they will be skipped |
|||
incubator = '~', meta = '~', |
|||
mediawiki = '~', sources = '~', |
|||
species = '~', beta = '~', |
|||
-- Legacy language codes used in sitecodes, remapped to standard Wikimedia language codes: |
|||
-- See https://meta.wikimedia.org/wiki/Special_language_codes for details |
|||
als = 'gsw', bat_smg = 'sgs', |
|||
fiu_vro = 'vro', be_x_old = 'be-tarask', |
|||
roa_rup = 'rup', zh_classical = 'lzh', |
|||
zh_yue = 'yue', zh_min_nan = 'nan', |
|||
zh_wuu = 'wuu', no = 'nb', |
|||
} |
|||
project = project:lower() |
|||
project = projLUT[project] or project -- correct the project name |
|||
local n = project:len() |
|||
local linkTable = {} |
|||
if entity and entity.sitelinks then -- See if entity exists, and that it has sitelinks |
|||
for _, sitelink in pairs(entity.sitelinks) do -- loop over all sitelinks |
|||
local site = sitelink.site |
|||
local m = site:len() - n |
|||
local proj = site:sub(m +1) -- project part of the siteID |
|||
if proj == project then -- proj matches desired "project" |
|||
local lang = site:sub(1, m) -- language part of the siteID |
|||
lang = langLUT[lang] or lang:gsub('_','-') |
|||
if lang ~= '~' then -- proj matches desired "project" |
|||
linkTable[lang] = sitelink.title |
|||
end |
|||
end |
|||
end |
|||
end |
end |
||
return linkTable |
|||
if (not args.capitalization) or (mw.text.trim(args.capitalization) == "") then |
|||
args.capitalization = "none" |
|||
end |
|||
args.item = mw.text.trim(args.item or '') |
|||
return p._getLabel(args.item, args.lang, args.link, args.capitalization, args.show_id) |
|||
end |
end |
||
--[[---------------------------------------------------------------- |
|||
--[[ |
|||
_aliases |
|||
_sitelinks |
|||
This function returns a table of |
This function returns a table of aliases for a single language |
||
Inputs: |
Inputs: |
||
1: item - wikidata's item's q- |
1: item - wikidata's item's q-id or entity class |
||
2: lang - language code, like 'en' or 'de' |
|||
2: project - "wikipedia", "wikisource", "wikiquote", "wikibooks", "wikinews", "wikiversity", |
|||
"wikivoyage", "wiktionary", "commons", "mediawiki", "wikispecies", "wikidata", etc. |
|||
Output: |
Output: |
||
Table with language fields |
Table of aliases with language fields |
||
]] |
]] |
||
function p. |
function p._aliases(item, lang) |
||
local entity |
local entity |
||
if type(item) == 'string' then -- "item" is a q-id |
|||
-- get entity |
|||
entity = mw.wikibase.getEntity(item) |
|||
if type(item)=='string' then -- "item" is a q-code |
|||
entity = mw.wikibase.getEntity(item); |
|||
else |
else |
||
entity = item -- "item" is the entity |
entity = item -- "item" is the entity |
||
item = entity.id -- look-up q-code |
|||
end |
end |
||
local aliasTable = {} |
|||
if entity and entity.aliases then -- See if there is an entity and that is has aliases |
|||
-- get project code |
|||
if entity.aliases[lang] then -- See if it has English Aliases |
|||
local LUT = {wikipedia='wiki', commons='commonswiki', mediawiki='mediawikiwiki', wikispecies='specieswiki', wikidata='wikidatawiki'} |
|||
for _, alias in pairs(entity.aliases[lang]) do -- Make a loop around the English aliases |
|||
project = string.lower(project) |
|||
table.insert(aliasTable, alias.value) -- Create a table of English aliases |
|||
if LUT[project] then -- correct the project name |
|||
project=LUT[project] |
|||
end |
|||
local n = string.len(project); |
|||
local s ={} |
|||
if entity and entity.sitelinks then -- See if entity exists, and that it has sitelinks |
|||
for _, sitelink in pairs(entity.sitelinks) do -- loop over all sitelinks |
|||
local site = sitelink.site |
|||
local lang = mw.ustring.sub( site, 1, mw.ustring.len(site) - n ) -- language part of the siteID |
|||
local proj = mw.ustring.sub( site, mw.ustring.len(site) - n + 1 ) -- project part of the siteID |
|||
if proj == project then -- proj matches desired "project" |
|||
s[lang] = sitelink.title |
|||
end |
end |
||
end |
end |
||
end |
end |
||
return |
return aliasTable |
||
end |
end |
||
--====================================================================== |
|||
--=== Invoke functions for use from wikitext, e.g., templates ========== |
|||
---===================================================================== |
|||
--[[ |
--[[ |
||
getLabel |
|||
This function returns a label translated to desired language, created based on wikidata |
|||
Usage: |
|||
{{#invoke:Wikidata label|getLabel|item=Q...|lang=..|link_style=..|capitalization=..}} |
|||
Parameters |
|||
1: wikidata's item's q-id (required) |
|||
2: language (optional; default {{int:lang}}) |
|||
3: link_style: "wikipedia" (default), "Wikidata", "Commons", or "-" (no link) |
|||
4: capitalization - can be "uc", "lc", "tc", "ucfirst", "lcfirst" |
|||
Error Handling: |
|||
Bad q-id will result in displayed error |
|||
]] |
|||
function p.getLabel(frame) |
|||
local args = getArgs(frame) |
|||
return p._getLabel(args.item, args.lang, args.link, args.capitalization, args.show_id) |
|||
end |
|||
--[[------------------------------------------------------------------------------- |
|||
sitelinks |
sitelinks |
||
Line 251: | Line 469: | ||
Inputs: |
Inputs: |
||
1: item - wikidata's item's q- |
1: item - wikidata's item's q-id or entity class |
||
2: project - "wikipedia" (or "wiki"), "wikisource", "wikiquote", "wikibooks", "wikinews", "wikiversity", "wikivoyage", "wiktionary", etc. |
2: project - "wikipedia" (or "wiki"), "wikisource", "wikiquote", "wikibooks", |
||
"wikinews", "wikiversity", "wikivoyage", "wiktionary", etc. |
|||
Output: |
Output: |
||
Line 258: | Line 477: | ||
]] |
]] |
||
function p.sitelinks(frame) |
function p.sitelinks(frame) |
||
local |
local args = getArgs(frame) |
||
local sitelinks = p._sitelinks(args.item, args.project) |
|||
local s = {} |
|||
local sitelinkList = {} |
|||
for i, j in pairs(sitelinks) do |
|||
for lang, sitelink in pairs(sitelinks) do |
|||
table.insert(s, i .. ':' .. j) |
|||
table.insert(sitelinkList, (lang=='' and sitelink) or (lang .. ':' .. sitelink)) |
|||
end |
end |
||
return table.concat( |
return table.concat(sitelinkList, ', ') |
||
end |
end |
||
--[[---------------------------------------------------------------------------- |
|||
--[[ |
|||
_aliases |
|||
This function returns a table of aliases for a single language |
|||
Inputs: |
|||
1: item - wikidata's item's q-code or entity class |
|||
2: lang - language code, like 'en' or 'de' |
|||
Output: |
|||
Table of aliases |
|||
]] |
|||
function p._aliases( item, lang ) |
|||
local entity |
|||
if type(item)=='string' then -- "item" is a q-code |
|||
entity = mw.wikibase.getEntity(item); |
|||
else |
|||
entity = item -- "item" is the entity |
|||
item = entity.id -- look-up q-code |
|||
end |
|||
local s = {} |
|||
if entity and entity.aliases then -- See if there is an entity and that is has aliases |
|||
if entity.aliases[lang] then -- See if it has English Aliases |
|||
for i, j in pairs(entity.aliases[lang]) do -- Make a loop around the English aliases |
|||
table.insert(s, j.value) -- Create a table of English aliases |
|||
end |
|||
end |
|||
end |
|||
return s |
|||
end |
|||
--[[ |
|||
aliases |
aliases |
||
Line 307: | Line 496: | ||
Inputs: |
Inputs: |
||
1: item - wikidata's item's q- |
1: item - wikidata's item's q-id or entity class |
||
2: lang - language code, like 'en' or 'de' |
2: lang - language code, like 'en' or 'de' |
||
Line 314: | Line 503: | ||
]] |
]] |
||
function p.aliases(frame) |
function p.aliases(frame) |
||
local args = getArgs(frame) |
|||
return table.concat(p._aliases(frame.args.item, frame.args.lang), ', ') |
|||
return table.concat(p._aliases(args.item, args.lang), ', ') |
|||
end |
end |
||
Latest revision as of 21:32, 9 March 2023
This module has a duplicate on Meta-Wiki. Please visit its documentation on Meta-Wiki for usage details and any additional information. Please keep the content and translations synchronized as much as possible. Thank you! |
This module has a duplicate on Wikidata. Please visit its documentation on Wikidata for usage details and any additional information. Please keep the content and translations synchronized as much as possible. Thank you! |
--[[
__ __ _ _ __ ___ _ _ _ _ _ _ _
| \/ | ___ __| |_ _| | ___ \ \ / (_) | _(_) __| | __ _| |_ __ _ | | __ _| |__ ___| |
| |\/| |/ _ \ / _` | | | | |/ _ (_) \ /\ / /| | |/ / |/ _` |/ _` | __/ _` | | |/ _` | '_ \ / _ \ |
| | | | (_) | (_| | |_| | | __/_ \ V V / | | <| | (_| | (_| | || (_| | | | (_| | |_) | __/ |
|_| |_|\___/ \__,_|\__,_|_|\___(_) \_/\_/ |_|_|\_\_|\__,_|\__,_|\__\__,_| |_|\__,_|_.__/ \___|_|
This module is intended to be the engine behind "Template:Label".
This module was copied from Commons please ask for changes there.
Please do not modify this code without applying the changes first at "Module:Wikidata label/sandbox" and testing
at "Module:Wikidata label/testcases".
Authors and maintainers:
* User:Jarekt - original version
]]
require('strict') -- used for debugging purposes as it detects cases of unintended global variables
--=============================================
--=== Internal functions ======================
--=============================================
---------------------------------------------------------------------------
-- Normalize input arguments by converting them all to lower case and
-- replacing space with "_" in the argument name. Also empty strings are
-- converted to nils. Arguments are collected from arguments passed to the
-- module and if missing from the template that calls the module
local function getArgs(frame)
local function normalize_input_args(input_args, output_args)
for name, value in pairs( input_args ) do
value = mw.text.trim(value) -- trim whitespaces from the beggining and the end of the string
if value ~= '' then -- nuke empty strings
if type(name)=='string' then
name = string.gsub( string.lower(name), ' ', '_')
end
output_args[name] = value
end
end
return output_args
end
local args = {}
args = normalize_input_args(frame:getParent().args, args)
args = normalize_input_args(frame.args, args)
return args
end
---------------------------------------------------------------------------
-- Function allowing for consistent treatment of boolean-like wikitext input.
-- It works similarly to Module:Yesno but does not assume val is a string
local function yesno(val, default)
if type(val) == 'boolean' then
return val
elseif type(val) == 'number' then
if val == 1 then
return true
elseif val == 0 then
return false
end
elseif type(val) == 'string' then
val = mw.ustring.lower(val) -- put in lower case
if val == 'no' or val == 'n' or val == 'false' or val == '0' then
return false
elseif val == 'yes' or val == 'y' or val == 'true' or val == '1' then
return true
end
end
return default
end
-------------------------------------------------------------------------
-- get message in a given language
-- INPUTS:
-- * msg - name of a message. For it to work [[MediaWiki:msg]] page need to be set up
-- * lang - translate message to language "lang"
-- * default - string to return in case this module is moved to a project where this message is not set
-- OUTPUT:
-- * translated message
local function getMessage(msg, lang, default)
msg = mw.message.new(msg):inLanguage(lang):plain()
return (msg == nil and default) or msg
end
---------------------------------------------------------------------------
-- use different sitelink call depending if you already have an entity or not
-- INPUTS:
-- * item and entity - entity id and entity: if full entity already uploded than use that
-- otherwise use entity id to look up sitelink
-- * lang - language of the project
-- OUTPUT:
-- * sitelink
local function getSitelink(item, entity, lang)
if entity and entity.getSitelink then -- if we have entity then use it
return entity:getSitelink(lang .. 'wiki')
else -- if no entity then use different function
return mw.wikibase.getSitelink(item, lang .. 'wiki')
end
end
---------------------------------------------------------------------------
-- use different sitelink call depending if you already have an entity or not
-- INPUTS:
-- * item and entity - entity id and entity: if full entity already uploded than use that
-- otherwise use entity id to look up sitelink
-- * prop - property for which to return the best statment
-- OUTPUT:
-- * value of the best statment (only from the first one)
local function getBestStatementsValue(item, entity, prop)
local statments
if entity then
statments = entity:getBestStatements(prop)
else
statments = mw.wikibase.getBestStatements(item, prop)
end
for _, statment in ipairs(statments) do
if statment and statment.mainsnak.datavalue.value then
return statment.mainsnak.datavalue.value
end
end
end
---------------------------------------------------------------------------
-- change capitalization of the label
-- INPUTS:
-- * label - label string
-- * capitalization - capitalization to be applied: allowed values are "tc", "lc",
-- "uc", "lcfirst", and "ucfirst". Any other value will return original string
-- * lang - language of the label
-- OUTPUT:
-- * value of the best statment (only from the first one)
local function apply_capitalization(label, capitalization, lang)
capitalization = string.lower(capitalization or 'none')
if capitalization == 'none' then
return label
elseif capitalization == 'uc' then
return mw.language.new(lang):uc(label)
elseif capitalization == 'lc' then
return mw.language.new(lang):lc(label)
elseif capitalization == 'tc' then -- title case
local new_label = {}
for _, word in ipairs(mw.text.split(label, ' ')) do
table.insert(new_label, mw.language.new(lang):ucfirst(word))
end
return table.concat(new_label, ' ')
elseif capitalization == 'ucfirst' then
return mw.language.new(lang):ucfirst(label)
elseif capitalization == 'lcfirst' then
return mw.language.new(lang):lcfirst(label)
end
return label
end
--[[-------------------------------------------------------------------------
get link based on user preference
INPUTS:
* link_type - can be :
* "wikidata" - link to wikidata
* "wikipedia" - link to wikipedia (language dependent)
* "wikidata talk" - link to wikidata talk page
* "commons" - link to commons (try sitelink then commons category then commons gallery)
* "commonscat" - link to commons (try commons category then commons gallery)
* "-" - means no link
* item - entity ID (always provided)
* entity - whole entity. It can be nil if whole entity is not loaded
* langList - language fallback list for preferred language (required)
OUTPUT:
* link - link to the wikimedia page
]]
local function getLink(link_type, item, entity, langList)
local link, eLink
link_type = mw.ustring.lower(link_type or '')
local item_type = mw.ustring.sub(item, 1, 1) -- first letter prefix of item entity ID: 'Q', 'P' or 'M'
if item_type == 'M' then
eLink='c:Special:EntityPage/'..item
elseif item_type == 'Q' then
eLink='d:'..item -- wikibase entity page link
elseif item_type == 'P' then
eLink='d:Property:'..item -- wikibase entity page link
else
eLink='d:Special:EntityPage/'..item
end
if link_type == '-' then -- allow different link formats
link = '' -- no link
elseif link_type == 'wikidata' or item_type == 'M' then
link = eLink -- link to wikibase entity page
elseif link_type == 'wikidata talk' and item_type == 'P' then
link = 'd:Property talk:'.. item -- link to wikidata property talk page
elseif link_type == 'wikidata talk' then
link = 'd:Talk:'..item -- link to wikidata talk page
elseif link_type == 'commons' or link_type == 'commonscat' then
--[[
When link_type == 'commons' we try the following links (in specified order):
1) commons sitelink
2) P373 "Commons Category" claims
3) P935 "Commons Gallery" claims
Since most items have a commons sitelink we never have to look for claims
When link_type == 'commonscat' we try to maximize chances of commons link being a category, so we
try the following links (in specified order):
1) commons sitelink, which is kept if it points to a category
2) P373 "Commons Category" claims
3) commons sitelink (which does not point to a category)
4) P935 "Commons Gallery" claims
Since most pages have a commons sitelink we never have to look for claims
]]
local sLink = getSitelink(item, entity, 'commons') -- look for sitelink to commons
if sLink then
sLink = 'c:'..sLink
if (link_type == 'commons') or (link_type == 'commonscat' and mw.ustring.find(sLink, 'Category:')) then
link = sLink
end
end
if not link then -- try linking to P373 "Commons Category"
local cat = getBestStatementsValue(item, entity, 'P373')
link = (cat ~= nil and 'c:Category:' .. cat) or nil
end
link = link or sLink
if not link then -- try linking to P935 "Commons Gallery"
link = getBestStatementsValue(item, entity, 'P935')
end
end
if not link then -- apply default "Wikipedia" link type
for _, language in ipairs(langList) do
local sitelink = getSitelink(item, entity, language)
if sitelink then
link = 'w:'.. language ..':'.. sitelink
break
end
end
end
return link or eLink -- no wiki sitelink, so link to wikidata
end
--=============================================
--=== External functions ======================
--=============================================
local p = {}
--======================================================================
--=== API functions for use from other Scribunto modules ===============
--======================================================================
--[[
_getLabel
This function returns a label translated to desired language, created based on wikidata
Inputs:
1: item - wikidata's item's q-id or entity class
2: lang - desired language of the label
3: link_type - link style. Possible values (case-insensitive): "wikipedia", "wikidata", "Commons", or "-" (no link)
4: capitalization - can be "uc" (upper case), "lc" (lower case), "ucfirst" (upper case for the first letter),
"lcfirst" (lower case for the first letter), or 'none' (default)
Error Handling:
Bad q-id will result in displayed error
]]
function p._getLabel(item, lang, link_type, capitalization, show_id)
local entity, s, link, label, language, desc
-- clean up the input parameters
if type(item) ~= 'string' then -- "item" is not a q-id
entity = item -- "item" must be the entity
item = entity.id -- look-up q-id
elseif tonumber(item) then -- if it is just the number then add "Q" in front
item = 'Q'..item
end
item = mw.ustring.gsub(mw.ustring.upper(item), 'PROPERTY:P', 'P') -- make all the properties the same and capitalize
if not lang then
label, lang = mw.wikibase.getLabelWithLang(item)
end
if not lang then -- if still no language
lang = mw.getCurrentFrame():callParserFunction("int","lang") -- get user's chosen language
label = nil
end
-- build language fallback list
lang = mw.ustring.lower(lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList, 1, lang)
-- get label (visible part of the link)
if not label then
for _, language in ipairs(langList) do -- loop over language fallback list looking for label in the specific language
if entity then
label = entity:getLabel(language)
else
label = mw.wikibase.getLabelByLang(item, language)
end
if label then break end -- label found and we are done
end
end
if label then -- wikitext-escape the label if we have one
label = mw.text.nowiki(label)
end
if not label then -- no labels found, so just show the q-id
label = item
elseif show_id then -- add id
show_id = yesno(show_id,false)
if show_id then
local wordsep = getMessage('Word-separator', lang, ' ')
local id = mw.message.new('parentheses', item):inLanguage(lang):plain()
id = (id~=nil and id) or ('('..item..')') -- in case this module is moved to a project where {{int:parenthesis}} is not set
label = label .. wordsep .. "<small>" .. id .. "</small>"
end
end
label = apply_capitalization(label, capitalization, lang)
-- look for description
if entity and entity.descriptions and lang then
for _, language in ipairs(langList) do
if entity.descriptions[language] then
desc = entity.descriptions[language].value
break
end
end
else
desc = mw.wikibase.getDescription(item)
end
if desc and link_type ~= '-' then -- wikitext-escape the description if we have one
desc = mw.text.nowiki(desc) -- add description as hover text
label = '<span title="' .. desc .. '">' .. label .. '</span>'
end
-- return the results
if link_type == '-' then
return label -- return just the label
else
link = getLink(link_type, item, entity, langList)
return '[[' .. link .. '|' .. label .. ']]' -- return link
end
end
--[[-------------------------------------------------------------------------------
_sitelinks
This function returns a table of sitelinks for a single project organized by language
Inputs:
1: item - wikidata's item's q-id or entity class
2: project - (case-insensitive) one of: "wikipedia", "wikisource", "wikiquote", "wikibooks", "wikinews",
"wikiversity", "wikivoyage", "wiktionary", "commons", "mediawiki", "wikispecies", "wikidata", etc.
Output:
Table of sitelinks with language fields
Output:
Table of sitelinks with language fields
See also
* [https://foundation.wikimedia.org/wiki/Special:SiteMatrix] for the full list of supported interwikis.
* [https://dumps.wikimedia.org/backup-index.html] for the full list of sitecodes (used in database dumps).
]]
function p._sitelinks(item, project)
local entity, sitelink
-- get entity
if type(item) == 'string' then -- "item" is a q-id
entity = mw.wikibase.getEntity(item)
else
entity = item -- "item" is the entity
end
-- convert from english project name to proproject code
local projLUT = {
wikipedia = 'wiki', commons = 'commonswiki',
foundation = 'foundationwiki', mediawiki = 'mediawikiwiki',
wikispecies = 'specieswiki', wikidata = 'wikidatawiki',
incubator = 'incubatorwiki', oldwikisource = 'sourceswiki',
}
local langLUT = {
-- These are not language codes before the 'wiki' or 'wikiversity' suffix in a sitecode:
foundation = '~', commons = '~', -- they will be skipped
incubator = '~', meta = '~',
mediawiki = '~', sources = '~',
species = '~', beta = '~',
-- Legacy language codes used in sitecodes, remapped to standard Wikimedia language codes:
-- See https://meta.wikimedia.org/wiki/Special_language_codes for details
als = 'gsw', bat_smg = 'sgs',
fiu_vro = 'vro', be_x_old = 'be-tarask',
roa_rup = 'rup', zh_classical = 'lzh',
zh_yue = 'yue', zh_min_nan = 'nan',
zh_wuu = 'wuu', no = 'nb',
}
project = project:lower()
project = projLUT[project] or project -- correct the project name
local n = project:len()
local linkTable = {}
if entity and entity.sitelinks then -- See if entity exists, and that it has sitelinks
for _, sitelink in pairs(entity.sitelinks) do -- loop over all sitelinks
local site = sitelink.site
local m = site:len() - n
local proj = site:sub(m +1) -- project part of the siteID
if proj == project then -- proj matches desired "project"
local lang = site:sub(1, m) -- language part of the siteID
lang = langLUT[lang] or lang:gsub('_','-')
if lang ~= '~' then -- proj matches desired "project"
linkTable[lang] = sitelink.title
end
end
end
end
return linkTable
end
--[[----------------------------------------------------------------
_aliases
This function returns a table of aliases for a single language
Inputs:
1: item - wikidata's item's q-id or entity class
2: lang - language code, like 'en' or 'de'
Output:
Table of aliases with language fields
]]
function p._aliases(item, lang)
local entity
if type(item) == 'string' then -- "item" is a q-id
entity = mw.wikibase.getEntity(item)
else
entity = item -- "item" is the entity
end
local aliasTable = {}
if entity and entity.aliases then -- See if there is an entity and that is has aliases
if entity.aliases[lang] then -- See if it has English Aliases
for _, alias in pairs(entity.aliases[lang]) do -- Make a loop around the English aliases
table.insert(aliasTable, alias.value) -- Create a table of English aliases
end
end
end
return aliasTable
end
--======================================================================
--=== Invoke functions for use from wikitext, e.g., templates ==========
---=====================================================================
--[[
getLabel
This function returns a label translated to desired language, created based on wikidata
Usage:
{{#invoke:Wikidata label|getLabel|item=Q...|lang=..|link_style=..|capitalization=..}}
Parameters
1: wikidata's item's q-id (required)
2: language (optional; default {{int:lang}})
3: link_style: "wikipedia" (default), "Wikidata", "Commons", or "-" (no link)
4: capitalization - can be "uc", "lc", "tc", "ucfirst", "lcfirst"
Error Handling:
Bad q-id will result in displayed error
]]
function p.getLabel(frame)
local args = getArgs(frame)
return p._getLabel(args.item, args.lang, args.link, args.capitalization, args.show_id)
end
--[[-------------------------------------------------------------------------------
sitelinks
This function returns a comma separated list of sitelinks for a single project organized by language
Its main purpose is to help with testing of _sitelinks function.
Usage:
{{#invoke:Wikidata label|sitelinks|item=Q...|project=..}}
Inputs:
1: item - wikidata's item's q-id or entity class
2: project - "wikipedia" (or "wiki"), "wikisource", "wikiquote", "wikibooks",
"wikinews", "wikiversity", "wikivoyage", "wiktionary", etc.
Output:
comma separated list
]]
function p.sitelinks(frame)
local args = getArgs(frame)
local sitelinks = p._sitelinks(args.item, args.project)
local sitelinkList = {}
for lang, sitelink in pairs(sitelinks) do
table.insert(sitelinkList, (lang=='' and sitelink) or (lang .. ':' .. sitelink))
end
return table.concat(sitelinkList, ', ')
end
--[[----------------------------------------------------------------------------
aliases
This function returns a comma separated list of aliases for a single language
Its main purpose is to help with testing of _aliases function.
Usage:
{{#invoke:Wikidata label|aliases|item=Q...|lang=..}}
Inputs:
1: item - wikidata's item's q-id or entity class
2: lang - language code, like 'en' or 'de'
Output:
Comma separated list of aliases
]]
function p.aliases(frame)
local args = getArgs(frame)
return table.concat(p._aliases(args.item, args.lang), ', ')
end
return p