Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Core: Difference between revisions

From Neodyland Wiki
add parseStatements function
move core.langWrapper from Module:Information and add a lot of documentation
Line 6: Line 6:
  |_|  |_|\___/ \__,_|\__,_|_|\___(_)\____\___/|_|  \___|
  |_|  |_|\___/ \__,_|\__,_|_|\___(_)\____\___/|_|  \___|
                                                          
                                                          
This module is intended as collection of core functions shared among several Lua modules  
Core is a meta-module that consists of common and useful Lua functions that can
creating infobox templates on Commons.  
be used in many Lua scripts. It was writen as a core of several Lua  
modules for creating file infobox templates on Commons. Many of the functions
are bare-bones versions of full functions found in other modules.


Authors and maintainers:
Authors and maintainers:
Line 16: Line 18:


------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Based on frame structure create "args" table with all the input parameters.
--[[
-- All inputs are not not case-sensitive and underscored are treated the same  
Based on frame structure create "args" table with all the input parameters:
-- way as speces. Input values are trimmed and empty string are converted to  
* table keys - equivalent to template parameters are converted to lower case
-- nils. If "lang" is not provided than we substitute user's prefered language.
                so they will not be case-sensitive.
                Also underscored are treated the same way as speces.  
* table values - input values are trimmed (whitespaces removed from the beggining
                and the end) and empty string are converted to nils.  
If "lang" is not provided than we substitute user's prefered language.
 
This function collects inputs from both frame and frame's parent. See
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame:getParent .
If both structures have the same field than value from "frame" takes priority.
 
Inputs:
1) frame - frame objects see below for details
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame-object
 
See also: Module:Arguments on enWiki - which is much larger single purpose module
]]
function core.getArgs(frame)
function core.getArgs(frame)
local function normalize_input_args(input_args, output_args)
local function normalize_input_args(input_args, output_args)
Line 54: Line 71:
   1: args - table with translations by language
   1: args - table with translations by language
   2: lang - desired language (often user's native language)
   2: lang - desired language (often user's native language)
 
Outputs:
  1: label - returned label
  2: lang  - language of the label (langSwitchWithLang only)
]]
]]
function core.langSwitch(args, lang)
function core.langSwitchWithLang(args, lang)
local langList = mw.language.getFallbacksFor(lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList,1,lang)
table.insert(langList,1,lang)
for i,language in ipairs(langList) do
for i,language in ipairs(langList) do
if args[language] then
if args[language] then
return args[language]
return args[language], language
end
end
end
end
end
function core.langSwitch(args, lang)
local label, lang = core.langSwitchWithLang(args, lang)
return label
end
end


------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Function allowing for consistent treatment of boolean-like wikitext input.
--[[
-- It works similarly to Module:Yesno
display a language followed by a message. Like "English: Hello" with extensive HTML marking
Code equivalent to https://commons.wikimedia.org/wiki/Template:Description with only 3 inputs
Inputs:
  1) text - text to display
  2) textLang - language code for the above text
  3) inline - Optional, default is false. When set to true, forces the template to be displayed
    inline, so that it does not break the current paragraph (that makes possible to put several
descriptions side by side on a single line)
]]
function core.langWrapper(text, textLang, inline)
inline = core.yesno(inline, false)  and 'inline' or nil
local wordsep  = mw.message.new( "Word-separator" ):inLanguage(textLang):plain()
local LangName = mw.language.fetchLanguageName( textLang, textLang)
local language = mw.language.new( textLang )
local dir      = language:getDir() 
local ltag = mw.html.create('span')  -- bold language name string
:addClass('language') -- class: "language" and "en", "de" etc.
:addClass(textLang)  -- classes:  "en", "de" etc.
:wikitext('<b>' .. language:ucfirst(LangName)..':</b>')
local dtag = mw.html.create('div')
:addClass('description')      -- div.description is tracked by mw:Extension:CommonsMetadata
:addClass('mw-content-'..dir) -- mw-content-rtl and mw-content-ltr are defined in mediawiki-code (https://gerrit.wikimedia.org/r/c/mediawiki/core/+/208332)
:addClass(textLang)          -- not sure where "en", "de" etc. are defined
:attr('dir', dir)
:attr('lang', textLang)
:css('display', inline)
:wikitext(tostring(ltag) .. wordsep .. text)
return tostring(dtag)
end
 
------------------------------------------------------------------------------
--[[
Function allowing for consistent treatment of boolean-like wikitext input.
Inputs:
  1) val - value to be evaluated, outputs as a function of values:
true  : true  (boolean), 1 (number), or strings: "yes", "y", "true", "1"
false : false (boolean), 0 (number), or strings: "no", "n", "false", "0"
  2) default - value to return otherwise
See Also: It works similarly to Module:Yesno
]]
function core.yesno(val, default)
function core.yesno(val, default)
if type(val) == 'boolean' then
if type(val) == 'boolean' then
return val
return val
elseif type(val) == 'number' then
elseif type(val) == 'number' then
if val==1 then  
val = tostring(val)
return true
end
elseif val==0 then
if type(val) == 'string' then
return false
local LUT = {
yes=true , y=true , ['true'] =true , t=true , ['1']=true , on =true,
no =false, n=false, ['false']=false, f=false, ['0']=false, off=false }
    val = LUT[mw.ustring.lower(val)]  -- put in lower case
    if (val~=nil) then
return val
end
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
     end
     return default
     return default
Line 89: Line 152:


------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- read Commons Data:SOMENAME.tab dataset and look for message identified by a  
--[[
-- "key" in a language "lang". See editAtWikidata as an example.
Read Commons Data:SOMENAME.tab dataset and look for message identified by a  
"key" in a language "lang". See editAtWikidata for an example. It uses
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.ext.data
 
Inputs:
1) dataset - name of commons page in "data" namespace. for example "I18n/EditAt.tab"
for c:Data:I18n/EditAt.tab
2) key - which message to pull
3) lang - desired language of the message
Output: message as a string
]]
function core.formatMessage(dataset, key, lang)
function core.formatMessage(dataset, key, lang)
for _, row in pairs(mw.ext.data.get(dataset, lang).data) do
for _, row in pairs(mw.ext.data.get(dataset, lang).data) do
Line 101: Line 174:
end
end


-------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Assembles the "Edit at Wikidata" pen icon and returns it as wikitext string.
--[[
-- Dependencies: Data:I18n/EditAt.tab
Assembles the "Edit at Wikidata" pen icon with a link to Wikidata page or specific
property and returns it as wikitext string.
Inputs:
  1) entityID - wikidata entity object for a given page (output of wikibase.getEntity( id ))
  2) propertyID - string like 'P31' so the link will point to that specific property. Use ""
    to link to the whole page.
  3) lang - language of the "Edit at Wikidata"  message
Dependencies: Data:I18n/EditAt.tab
See Also: en:Module:EditAtWikidata
]]
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function core.editAtWikidata(entityID, propertyID, lang)
function core.editAtWikidata(entityID, propertyID, lang)
Line 111: Line 193:
end
end


-------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Assembles the "Edit at SDC" pen icon and returns it as wikitext string.
--[[
-- Dependencies: Data:I18n/EditAt.tab
Assembles the "Edit at SDC" pen icon with a link to a property in SDC part of the current file
-------------------------------------------------------------------------------
page, and returns it as wikitext string.
Inputs:
  2) propertyID - string like 'P31' so the link will point to that specific property. Use 'ooui-php-4'
    to link to the label section.
  3) lang - language of the "Edit at Wikidata"  message
Dependencies: Data:I18n/EditAt.tab
See Also: en:Module:EditAtWikidata
]]
function core.editAtSDC(propertyID, lang)
function core.editAtSDC(propertyID, lang)
local msg  = core.formatMessage('I18n/EditAt.tab', 'EditAtSDC', lang)
local msg  = core.formatMessage('I18n/EditAt.tab', 'EditAtSDC', lang)

Revision as of 05:56, 28 February 2021

Module documentation[ create · purge ]
This documentation is transcluded from Module:Core/doc.
--[[  
  __  __           _       _         ____               
 |  \/  | ___   __| |_   _| | ___ _ / ___|___  _ __ ___ 
 | |\/| |/ _ \ / _` | | | | |/ _ (_) |   / _ \| '__/ _ \
 | |  | | (_) | (_| | |_| | |  __/_| |__| (_) | | |  __/
 |_|  |_|\___/ \__,_|\__,_|_|\___(_)\____\___/|_|  \___|
                                                        
Core is a meta-module that consists of common and useful Lua functions that can 
be used in many Lua scripts. It was writen as a core of several Lua 
modules for creating file infobox templates on Commons. Many of the functions
are bare-bones versions of full functions found in other modules.

Authors and maintainers:
* User:Jarekt  
]]

local core = {}

------------------------------------------------------------------------------
--[[
Based on frame structure create "args" table with all the input parameters:
 * table keys - equivalent to template parameters are converted to lower case 
                so they will not be case-sensitive.
                Also underscored are treated the same way as speces. 
 * table values - input values are trimmed (whitespaces removed from the beggining 
                and the end) and empty string are converted to nils. 
If "lang" is not provided than we substitute user's prefered language.

This function collects inputs from both frame and frame's parent. See 
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame:getParent .
If both structures have the same field than value from "frame" takes priority.

Inputs:
	1) frame - frame objects see below for details
	https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame-object

See also: Module:Arguments on enWiki - which is much larger single purpose module
]]
function core.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)
	if (args.lang and mw.language.isSupportedLanguage(args.lang)) then 
		args.lang = string.lower(args.lang)
	else
		args.lang = frame:callParserFunction("int","lang")  -- get user's chosen language
	end
	return args
end

------------------------------------------------------------------------------
--[[
Simplified code equivalent to https://commons.wikimedia.org/wiki/Template:LangSwitch

Example usage:
  text = langSwitch({en='text in english', pl='tekst po polsku'}, lang)

Inputs:
  1: args - table with translations by language
  2: lang - desired language (often user's native language)
  
Outputs:
  1: label - returned label
  2: lang  - language of the label (langSwitchWithLang only)
]]
function core.langSwitchWithLang(args, lang)
	local langList = mw.language.getFallbacksFor(lang)
	table.insert(langList,1,lang)
	for i,language in ipairs(langList) do
		if args[language] then
			return args[language], language
		end
	end
end

function core.langSwitch(args, lang)
	local label, lang = core.langSwitchWithLang(args, lang)
	return label
end

------------------------------------------------------------------------------
--[[
display a language followed by a message. Like "English: Hello" with extensive HTML marking
Code equivalent to https://commons.wikimedia.org/wiki/Template:Description with only 3 inputs
Inputs:
  1) text - text to display
  2) textLang - language code for the above text
  3) inline - Optional, default is false. When set to true, forces the template to be displayed 
     inline, so that it does not break the current paragraph (that makes possible to put several 
	 descriptions side by side on a single line)
]]
function core.langWrapper(text, textLang, inline) 
	inline = core.yesno(inline, false)  and 'inline' or nil
	local wordsep  = mw.message.new( "Word-separator" ):inLanguage(textLang):plain()
	local LangName = mw.language.fetchLanguageName( textLang, textLang)
	local language = mw.language.new( textLang )
	local dir      = language:getDir()  
	local ltag = mw.html.create('span')  -- bold language name string
		:addClass('language') -- class: "language" and "en", "de" etc.
		:addClass(textLang)   -- classes:  "en", "de" etc.	
		:wikitext('<b>' .. language:ucfirst(LangName)..':</b>')
	local dtag = mw.html.create('div')
		:addClass('description')      -- div.description is tracked by mw:Extension:CommonsMetadata
		:addClass('mw-content-'..dir) -- mw-content-rtl and mw-content-ltr are defined in mediawiki-code (https://gerrit.wikimedia.org/r/c/mediawiki/core/+/208332)
		:addClass(textLang)           -- not sure where "en", "de" etc. are defined
		:attr('dir', dir)
		:attr('lang', textLang)
		:css('display', inline) 
		:wikitext(tostring(ltag) .. wordsep .. text)
	return tostring(dtag)
end

------------------------------------------------------------------------------
--[[
Function allowing for consistent treatment of boolean-like wikitext input.
Inputs:
  1) val - value to be evaluated, outputs as a function of values:
		true  : true  (boolean), 1 (number), or strings: "yes", "y", "true", "1"
		false : false (boolean), 0 (number), or strings: "no", "n", "false", "0"
  2) default - value to return otherwise
See Also: It works similarly to Module:Yesno
]]
function core.yesno(val, default)
	if type(val) == 'boolean' then
		return val
	elseif type(val) == 'number' then
		val = tostring(val)
	end
	if type(val) == 'string' then
		local LUT = {
			yes=true , y=true , ['true'] =true , t=true , ['1']=true , on =true,
			no =false, n=false, ['false']=false, f=false, ['0']=false, off=false }
	    val = LUT[mw.ustring.lower(val)]  -- put in lower case
	    if (val~=nil) then
			return val
		end
    end
    return default
end

------------------------------------------------------------------------------
--[[
Read Commons Data:SOMENAME.tab dataset and look for message identified by a 
"key" in a language "lang". See editAtWikidata for an example. It uses
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#mw.ext.data

Inputs:
 1) dataset - name of commons page in "data" namespace. for example "I18n/EditAt.tab" 
	for c:Data:I18n/EditAt.tab
 2) key - which message to pull
 3) lang - desired language of the message
Output: message as a string
]]
function core.formatMessage(dataset, key, lang)
	for _, row in pairs(mw.ext.data.get(dataset, lang).data) do
		local id, msg = unpack(row)
		if id == key then
			return mw.message.newRawMessage(msg):plain()
		end
	end
	error('Invalid message key "' .. key .. '"')
end

------------------------------------------------------------------------------
--[[
Assembles the "Edit at Wikidata" pen icon with a link to Wikidata page or specific 
property and returns it as wikitext string.
Inputs:
  1) entityID - wikidata entity object for a given page (output of wikibase.getEntity( id ))
  2) propertyID - string like 'P31' so the link will point to that specific property. Use "" 
     to link to the whole page. 
  3) lang - language of the "Edit at Wikidata"  message
Dependencies: Data:I18n/EditAt.tab
See Also: en:Module:EditAtWikidata
]]
-------------------------------------------------------------------------------
function core.editAtWikidata(entityID, propertyID, lang)
	local msg  = core.formatMessage('I18n/EditAt.tab', 'EditAtWikidata', lang)
	local link = 'https://www.wikidata.org/wiki/' .. entityID .. (propertyID == "" and "" or ("#" .. propertyID))
	return "&nbsp;[[File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="..msg.."|link="..link.."|"..msg.."]]"
end

------------------------------------------------------------------------------
--[[
Assembles the "Edit at SDC" pen icon with a link to a property in SDC part of the current file 
page, and returns it as wikitext string.
Inputs:
  2) propertyID - string like 'P31' so the link will point to that specific property. Use 'ooui-php-4' 
     to link to the label section. 
  3) lang - language of the "Edit at Wikidata"  message
Dependencies: Data:I18n/EditAt.tab
See Also: en:Module:EditAtWikidata
]]
function core.editAtSDC(propertyID, lang)
	local msg  = core.formatMessage('I18n/EditAt.tab', 'EditAtSDC', lang)
	local link =  mw.title.getCurrentTitle():fullUrl() .. (propertyID == "" and "" or ("#" .. propertyID))
	return "&nbsp;[[File:OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt="..msg.."|link="..link.."|"..msg.."]]"
end

-------------------------------------------------------------------------------
--[[
This function returns a label translated to desired language, created based on wikidata
Code equivalent to require("Module:Wikidata label")._getLabel

Inputs:
	1: item - wikidata's item's q-id or entity class
	2: userLang - desired language of the label
]]
function core.getLabel(item, userLang) 
	local label, link
	-- build language fallback list
	local langList = mw.language.getFallbacksFor(userLang)
	table.insert(langList, 1, userLang) 
	-- get label
	for _, lang in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
		label = mw.wikibase.getLabelByLang(item, lang)
		if label then break end                    -- label found and we are done
	end	
	label = label or item -- fallback value
	-- get link
	for _, lang in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
		link =  mw.wikibase.getSitelink(item, lang .. 'wiki')
		if link then
			link = mw.ustring.format('w:%s:%s', lang, link)
			break
		end
	end
	link = link or 'd:'..item -- fallback value
	-- look for description
	local desc = mw.wikibase.getDescription(item)
	if desc then  -- add description if we have one
		desc  = mw.text.nowiki(desc) -- add description as hover text
		label = '<span title="' .. desc .. '">' .. label .. '</span>'
	end
   return '[['..link..'|'..label..']]'
end

-------------------------------------------------------------------------------
--[[
Core component of many "get property value" functions
Example: (core.parse_statements(entity:getBestStatements( prop ), nil) or {nil})[1] would 
return the first best statement
Inputs:
 1: statements - can be provided by:
   * entity:getBestStatements( prop )
   * entity:getAllStatements( prop )
   * mw.wikibase.getBestStatements( item, prop )
   * mw.wikibase.getAllStatements( item, prop )
 2: lang - language code (like "en"), if provided than item IDs will be 
     changed to a label
Output:
 * table of strings or nil
]]
function core.parseStatements(statements, lang)
	local output = {}
	for _, statement in ipairs(statements) do
		if (statement.mainsnak.snaktype == "value") and (statement.rank ~= 'deprecated')  then
			local val = statement.mainsnak.datavalue.value
			if val.id then 
				val = val.id
				if lang ~= nil then
					val = core.getLabel(val, lang)
				end
			elseif val.text then
				val = val.text
			elseif val.amount then
				val = tonumber(val.amount)
			end
			table.insert(output, val)
		end
	end
	if #output==0 then return nil end
	return output
end

return core
Cookies help us deliver our services. By using our services, you agree to our use of cookies.