Module:GetShortDescription
{{#invoke:GetShortDescription|main |name= |only= |prefer= |fallback= |lang_italic= |lang_nocat= |lang_size= |lang_cat= |lang_rtl= |lang_no= }}
name
By providing only the required page name (including namespace), the module will look for an explicit {{short description}}
in that page, but if not found, will try to fetch the wikidata description. If neither are found, the result will be an empty string.
If the result is a wikidata description, and it is declared (at the source) as being of a foreign language (i.e. not en), the result will be appropriately formatted by Module:Lang (the module powering {{lang}}
), in accordance with MOS:OTHERLANG; see #Foreign language wikidata descriptions (below).
- Markup:
{{#invoke:GetShortDescription|main |name=Wikipedia}}
- Result: table
This is equivalent to stating |prefer=explicit
; see #prefer (below).
only
Providing a value for |only=
will limit the search to being only for the stated description. If no description is found, the result will be an empty string, unless a fallback is provided; see #fallback (below).
explicit
- Markup:
{{#invoke:GetShortDescription|main |name=Wikipedia |only=explicit }}
- Result: table
wikidata
- Markup:
{{#invoke:GetShortDescription|main |name=Wikipedia |only=wikidata }}
- Result: table
prefer
Providing a value for |prefer=
will initiate the search for the stated description, but try for the alternative if none is found. If no description is found, the result will be an empty string, unless a fallback is provided; see #fallback (below).
explicit or wikidata
- Markup:
{{#invoke:GetShortDescription|main |name=Wikipedia |prefer=explicit }}
- Result: table
wikidata or explicit
- Markup:
{{#invoke:GetShortDescription|main |name=Wikipedia |prefer=wikidata }}
- Result: table
fallback
If a value for |fallback=
is provided, and no description is found by the expressed route, the result will be the stated fallback.
only or fallback
- Markup:
{{#invoke:GetShortDescription|main |name=Example |only=explicit |fallback=This is a fallback }}
- Result:
prefer or fallback
- Markup:
{{#invoke:GetShortDescription|main |name=Example |prefer=wikidata |fallback=This is a fallback }}
- Result: table
Foreign language wikidata descriptions
Should a wikidata description be retrieved, which is declared (at the source) as being of a foreign language (i.e. not en), per MOS:OTHERLANG, the return will be formatted as appropriate by Module:Lang by default. This may be disabled with |lang_no=yes
or adjusted via the parameters for {{lang}}
: |lang_italic=
, |lang_nocat=
, |lang_size=
, |lang_cat=
and |lang_rtl=
; see lang's documentation for details.
Requiring this module
Instances when a table is returned
Providing a value for |objectify_alarm=
will cause alarming messages (red informational messages) to be returned as tables.
Providing a value for |report_redlinks=
will cause the return of a report instead of nothing in the event that the page named is nonexistent (i.e. a WP:REDLINK) and a search for a {{short description}}
template is processed.
A table will also be returned in the event that the module is instructed to |prefer=explicit
(its default), and returns a Wikidata description. If the reason for there being no explicit short description is because it was set to none; the table will include a value for table.none
See below for examples of these behaviors:
local getShortDescription = require( 'Module:GetShortDescription' ).main
local short_description = getShortDescription( {
-- required
name = 'page name',
-- optional
prefer = 'explicit' or 'wikidata',
only = 'explicit' or 'wikidata',
fallback = 'fallback',
objectify_alarm = true,
report_redlinks = true,
lang_no = 'yes',
-- {{lang}} options
lang_italic = <yes, no, unset, invert, default>,
lang_nocat = <yes, y, true, t, on, 1>,
lang_size = <CSS font-size e.g. '1.5em'>,
lang_cat = <no, n, false, f, off, 0>,
lang_rtl = <no (default), yes>
} )
-- If we've requested to report_redlinks or to objectify_alarm then
if type( short_description ) == 'table' then
if short_description.alarm then
-- An alarming message has been returned
local alarming_message = short_description.alarm
elseif short_description.redlink then
-- Do something about that
elseif short_description.wikidata then
-- A Wikidata description was returned without being explicitly requested
local wikidata_description = short_description.wikidata
if short_description.none then
-- Because the explicit short desc was 'none'
end
end
end
local function isEmpty(value) return value == nil or value == '' end
local function notEmpty(value) return not isEmpty(value) end
local function isNone(value) return value:lower() == 'none' end
local function alarmingMessage(message, preview)
message = '<span style="color:#d33">[[Module:GetShortDescription]] '..message..'.</span>'
if not preview then
message = message..'[[Category:Pages displaying alarming messages about Module:GetShortDescription]]'
end
return message
end
-- Grammatically reasonable concatenation of possible issues into one message per problematic link target.
local function previewWarning(args_name, quantity_of_things)
local message = ''
if quantity_of_things.params > 3 then
message = message..' with extraneous parameters'
end
if quantity_of_things.descriptions > 1 then
message = message..', declaring '..quantity_of_things.descriptions..' short descriptions'
end
if quantity_of_things.templates > 1 or notEmpty(message) then
message = 'has detected that [[:'..args_name..'|'..args_name..']] has '..
quantity_of_things.templates..' {{tlx|short description}}'..message
mw.addWarning(alarmingMessage(message, true))
end
end
local function getWikidataDescription(title, args, fallback)
local wikidata_id = mw.wikibase.getEntityIdForTitle(title)
if isEmpty(wikidata_id) then
return nil
end
local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang(wikidata_id)
if isEmpty(wikidata_description) then
return nil
end
local result = {wikidata = wikidata_description}
if isEmpty(args.lang_no) and notEmpty(wikidata_description_lang) and wikidata_description_lang ~= 'en' then
-- According to the docs this is a possibility...
result.wikidata = require('Module:Lang')._lang{
wikidata_description_lang,
wikidata_description,
italic = args.lang_italic,
nocat = args.lang_nocat,
size = args.lang_size,
cat = args.lang_cat,
rtl = args.lang_rtl
}
end
result.fellback = fallback
return result
end
local function getShortDescriptionTemplates(title_table)
local page_content = title_table:getContent()
-- Assume no content means a nonexistent title because it's cheaper than testing if it exists.
if isEmpty(page_content) then
return {redlink = true}
end
local contents_of_all_short_description_templates = {}
-- Because there could be any number of short description templates, and not all where there should be; get all the templates.
for template in page_content:gmatch('{%b{}}') do
local short_description_content = mw.ustring.match(template, '^{{%s*[Ss]hort description%s*|%s*(.-)%s*}}')
if notEmpty(short_description_content) then
-- Collect the contents of short description templates.
contents_of_all_short_description_templates[#contents_of_all_short_description_templates+1] = short_description_content
end
-- An opportunity for efficiency gain exists - to break if another type of template is found e.g. citation templates,
-- but on an appallingly formatted page, a short description template down by the categories would likely be missed.
end
return contents_of_all_short_description_templates
end
local function getShortDescription(args_name, args_name_title_table, title, title_table, fallback)
local contents_of_all_short_description_templates = {}
local redirected
-- Check for short description templates on redirect pages.
if title ~= args_name then
contents_of_all_short_description_templates = getShortDescriptionTemplates(args_name_title_table)
if contents_of_all_short_description_templates.redlink then
return contents_of_all_short_description_templates
end
redirected = false
end
if #contents_of_all_short_description_templates < 1 then
contents_of_all_short_description_templates = getShortDescriptionTemplates(title_table)
if notEmpty(redirected) then
redirected = true
end
end
if contents_of_all_short_description_templates.redlink then
return contents_of_all_short_description_templates
end
if #contents_of_all_short_description_templates < 1 then
return nil
end
local quantity_of_things = {
templates = #contents_of_all_short_description_templates,
descriptions = 0,
params = 0
}
local possible_short_descriptions = {}
-- Look through the short description templates:
for template_content_index, short_description_template_contents in ipairs(contents_of_all_short_description_templates) do
-- Split the contents at pipes and trim.
local short_description_template_params = mw.text.split(short_description_template_contents, '%s*|%s*')
if #short_description_template_params > quantity_of_things.params then
quantity_of_things.params = #short_description_template_params
end
possible_short_descriptions[template_content_index] = {}
-- Look through the params:
for i, param in ipairs(short_description_template_params) do
if param == 'noreplace' or mw.ustring.match(param, '^2%s*=%s*noreplace$') then
-- Take note of 'noreplace'-ing for establishment of hierarchy later.
possible_short_descriptions[template_content_index].noreplace = true
else
local has_equals = param:match('=')
if not has_equals or param:match('^1') then
-- Grab the short description.
if has_equals then
param = mw.ustring.gsub(param, '^1%s*=%s*', '')
end
-- If the template has both a numbered and an unnumbered short description;
-- whichever comes last (ltr) will be used by that template, so overwriting works out great.
possible_short_descriptions[template_content_index].description = param
-- And we want to know the total quantity of descriptions being declared.
quantity_of_things.descriptions = quantity_of_things.descriptions + 1
end
end
end
end
local short_descriptions = {}
-- Look through the possible short descriptions for definite short descriptions,
-- and prepare for working out which of possibly multiple short descriptions is actually being applied for the page:
for i, possible_short_description in ipairs(possible_short_descriptions) do
if possible_short_description.description then
-- If a description is 'noreplace'-ing or 'none'; demote it.
if (possible_short_description.noreplace or isNone(possible_short_description.description)) and
#possible_short_descriptions > 1 then
-- But don't demote it if it's already at the bottom.
if i > 1 then
table.insert(short_descriptions, #short_descriptions, possible_short_description)
else
short_descriptions[#short_descriptions+1] = possible_short_description
end
else
short_descriptions[#short_descriptions+1] = possible_short_description
end
end
end
-- Let previewWarning() work out if these numbers are bad.
previewWarning(args_name, quantity_of_things)
if #short_descriptions >= 1 then
-- Pop!
local short_description = short_descriptions[#short_descriptions].description
if notEmpty(short_description) then
return {explicit = short_description, fellback = fallback, redirected = redirected}
end
end
return nil
end
local function isSisterProjectLink(title)
local sister_project_prefixes = {
'wiktionary', 'wikt',
'wikinews', 'n',
'wikibooks', 'b',
'wikiquote', 'q',
'wikisource', 's',
'wikispecies', 'species',
'wikiversity', 'v',
'wikivoyage', 'voy',
'commons', 'c',
'wikidata', 'd',
'mediawikiwiki', 'mw',
'wikimedia', 'foundation', 'wmf',
'meta', 'm',
'incubator',
'phabricator', 'phab'
}
local pre_colon = title:match('^(%a+):')
if pre_colon then
for i, sister in ipairs(sister_project_prefixes) do
if pre_colon == sister then
return true
end
end
end
return false
end
-- Literally testing if title_table.isRedirect can be expensive;
-- processing this way resolves (multiple) redirects without the possibly expensive check.
local function getTitleAndTable(orig_name)
local title_table = mw.title.new(orig_name)
title_table = title_table.redirectTarget or title_table
local title = title_table.prefixedText
if title == orig_name then
return title, title_table
end
return getTitleAndTable(title)
end
local function getDescription(args)
local args_name = args.name
if isEmpty(args_name) then
return {alarm = 'requires a page name (including namespace)'}
end
-- Keep the orginal name, cleaned up, and its title_table for later.
local args_name_title_table = mw.title.new(args_name)
args_name = args_name_title_table.prefixedText
if isSisterProjectLink(args_name) then
return nil
end
local title, title_table = getTitleAndTable(args_name)
if title ~= args_name then
if isSisterProjectLink(title) then
return nil
end
end
local only = args.only
local prefer = args.prefer or 'explicit'
-- Pass args_name to getShortDescription() so previewWarning()s won't be confusing for redirects.
if notEmpty(only) then
if only == 'explicit' then
return getShortDescription(args_name, args_name_title_table, title, title_table)
end
if only == 'wikidata' then
return getWikidataDescription(title, args)
end
return {alarm = 'accepts either "explicit" or "wikidata" as the value of |only='}
end
if notEmpty(prefer) then
if prefer == 'explicit' then
local short_description = getShortDescription(args_name, args_name_title_table, title, title_table)
if notEmpty(short_description) then
-- Assume a Wikidata search would be a bad idea for an assumed nonexistent title.
if short_description.redlink or (not isNone(short_description.explicit) or args.none_is_valid) then
return short_description
end
end
return getWikidataDescription(title, args, true)
end
if prefer == 'wikidata' then
return getWikidataDescription(title, args) or getShortDescription(args_name, args_name_title_table, title, title_table, true)
end
return {alarm = 'accepts either "explicit" or "wikidata" as the value of |prefer='}
end
end
local function main(args)
local result = getDescription(args)
if notEmpty(result) then
if result.alarm then
result.alarm = alarmingMessage(result.alarm)
end
if args.stringify then
if result.alarm then
result = result.alarm
else
result = result.explicit or result.wikidata
if args.none_is_nil and isNone(result) then
result = nil
end
end
elseif not result.alarm and args.none_is_nil then
local description = result.explicit or result.wikidata
if description and args.none_is_nil and isNone(description) then
result = nil
end
end
end
return result
end
local p = {}
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame)
if isEmpty(args) then
return alarmingMessage('could not getArgs') -- This really would be alarming.
end
return main(args)
end
return p