Module:Programma
Appearance
Documentation for this module may be created at Module:Programma/doc
local mWikidata = require('Module:Wikidata')
local getArgs = require('Module:Arguments').getArgs
local conf = mw.loadData('Module:Programma/Cunfiguratzione')
local p = {}
--------------------------------------------------------------------------------
local UNKNOWN = -1 -- Non faghet a identificare sa litzèntzia
local FREE = 1 -- Est una litzèntzia de programma lìberu
local PROPRIETARY = 2 -- Est una litzèntzia de programma propietàriu
local MAX_RECURSION = 4 -- [[Module:Programma/man#Cunsideratziones implementativas]]
local UNKNOWN_WD_LANGUAGE = "[[Categoria:Limbàgiu de programmatzione dae Wikidata non prevìdidu]]"
local UNKNOWN_WD_LICENSE = ""
local UNKNOWN_WD_TOOLKIT = "[[Categoria:Toolkit o framework de s'interfache gràfica non prevìdidu]]"
local FREE_WITHOUT_LANGUAGE = '[[Categoria:Programma lìberu chene limbàgiu]]'
local TEMPLATE_UNKNOWN_ARG_WARN = " <span style=\"font-size:75%\">(non in [[Template:Programma#Limbàgios|lista]])</span>"
local TEMPLATE_UNKNOWN_ARG_CAT = "[[Categoria:Programma in limbàgiu non reconnotu]]"
local LICENSE_CAT = "Programma cun litzèntzia %s"
-- "Programma cun litzèntzia GNU GPL"
local LICENSE_CAT_SHORTER = "Programma %s"
-- "Programma freeware"
local YEAR_CAT = 'Programma de su %d'
-------------------------------- Isgabutzinu ------------------------------------
--[[
* Get the ID from a statement (claim) of type wikibase-id
*
* @param table Wikibase claim
* @return string|nil
]]
local function statementQID( claim )
return claim.mainsnak.datavalue and claim.mainsnak.datavalue.value.id
end
--[[
* @param string Wikidata element
* @TODO ora prende il primo, a prescindere dalla lingua (credo).
* @return string
]]
local function shortWikidataLabel(from)
local s = ''
local label = mw.wikibase.label(from)
local sitelink = mw.wikibase.sitelink(from) or label
if string.len(label) > 10 then
label = mWikidata._getProperty( { 'P1813', n = 1, from = from } ) or label
end
return "[[" .. sitelink .. "|" .. label .. "]]"
end
--[[
* @param v bool
* @return string
]]
local function yesNo(v)
return v and 'eja' or 'nono'
end
--[[
* @param v bool
* @return string|nil
]]
local function yesNoNil(v)
if v == nil then
return nil
end
return yesNo(v)
end
--[[
* Poi non ditemi che PHP fa schifo. asd.
* Sembra che l'operatore "#" ogni tanto non vada col Modulo:Wikidata.
* 00:28, 28 feb 2017 Valerio Bozzolan
]]
local function count(t)
local i = 0
for _,_ in pairs(t) do
i = i + 1
end
return i
end
--[[
* Restituisce una tabella completa di proprietà non formattate.
* @return {}|nil
* ]]
local function rawProperties(from, property)
return mWikidata._getProperty({property, from = from, formatting = 'raw'}, true)
end
local function onlySoftwareArguments(frame)
return getArgs(frame, {wrappers = 'Template:Programma'} )
end
--[[
* Torrat PETZI s'argumentu `from` de donare a funtzionalidades vàrias de su Module:Wikidata
* @param frame table
* @return string|nil
]]
local function fromItem(frame)
return getArgs(frame).from
end
--[[
* Anàlogu a fromItem() ma benit recuperadu dae Property:P301 (category's main topic).
*
* @return string|nil
]]
local function fromItemMainTopic()
local from = mWikidata._getClaims('P301')
from = from and from[1]
if not from then
error("Custa no est una categoria, o mancat sa propiedade Wikidata P301")
end
return statementQID(from)
end
--[[
* Formatat una categoria.
*
* @param category string Primu argumentu per sprinf
* @param part string Placeholder per sprintf
* @param man boolean Mustrare petzi sa categoria in càmbiu de categorizare?
* @return string
]]
local function formatCategory(category, part, man)
local colon = man and ':' or ''
return "[[" .. colon .. "Categoria:" .. string.format(category, part) .. "]]"
end
------------------------------- Frontend ---------------------------------------
function p.shouldHaveALanguage(frame)
return yesNo( p._shouldHaveALanguage( onlySoftwareArguments(frame) ) )
end
function p.specifiesALanguage(frame)
return yesNo( p._specifiesALanguage( onlySoftwareArguments(frame) ) )
end
function p.specifiesAToolkit(frame)
return yesNo( mWikidata._getClaims('P277') )
end
function p.isFreeSoftware(frame)
return yesNoNil( p._isFreeSoftware( onlySoftwareArguments(frame) ) )
end
function p.hasAFreeLicense(frame)
return yesNoNil( p._hasAFreeLicense( fromItem(frame) ) )
end
function p.hasAProprietaryLicense(frame)
return yesNoNil( p._hasAProprietaryLicense( fromItem(frame) ) )
end
function p.languageCategories( frame )
return p._languageCategories( fromItem( frame ) )
end
--[[
* Categoriza un'artìculu'.
* @return string|nil
]]
function p.categories(frame)
if p._categorize( onlySoftwareArguments(frame) ) then
return p.licenseCategories(frame) .. p.toolkitCategories(frame) .. p.yearsCategories(frame)
end
return nil
end
function p.wikidataCategoriesFromMainTopic(frame)
local s = p._wikidataCategories( fromItemMainTopic() )
return s .. string.format('[[Categoria:P301 %s Wikidata]]', s and 'lèghida dae' or 'mancat in')
end
--[[
* Categoriza una pàgina cale si siat.
* @return string|nil
]]
function p.wikidataCategories(frame)
return p._wikidataCategories( fromItem(frame) ) or nil
end
--[[
* Totu sas categorias chi si podent aplicare dae Wikidata.
*
* Pro como bi sunt petzi sas litzèntzias, ma inoghe bi depent andare fintzas sos limbàgios.
*
* @param from string|nil Wikidata Item
* @return string
]]
function p._wikidataCategories(from)
return p._licenseCategories(from) .. p._languageCategories(from) .. p._toolkitCategories(from) .. p._yearsCategories(from)
end
--[[
* Categorias ligadas a sas litzèntzias.
* @return string
]]
function p.licenseCategories(frame)
return p._licenseCategories( fromItem(frame) )
end
--[[
* Categorias ligadas a su toolkit.
* @return string
]]
function p.toolkitCategories(frame)
return p._toolkitCategories( fromItem(frame) )
end
--[[
* Categoria ligada a s'annu de fundatzione.
* @return string
]]
function p.yearsCategories(frame)
return p._yearsCategories( fromItem(frame), onlySoftwareArguments(frame).DataPrimaVersione )
end
--[[
* Limbàgios de programmatzione.
*
* @return string
]]
function p.languages(frame)
local s = ''
local args = frame and onlySoftwareArguments(frame)
local categorize = p._categorize(args)
local is_free = p._isFreeSoftware(args)
local tl_has = p._templateHasLanguages(args) and true or false --exclude nil
local tl_languages = p._getTemplateLanguages(args)
local wd_languages = mWikidata._getClaims('P277')
-- Est s'ispàtziu de nùmene printzipale?
local nszero = mw.title.getCurrentTitle().namespace == 0
-- Su template s'est arrichidu gràtzias a Wikidata?
local improved = false
-- Totu sos limbàgios sunt identificados dae Wikidata e dae su template?
local tl_allFound = true
local wd_allFound = true
-- Su template no ammustrat perunu limbàgiu?
local noLanguages = not tl_has and not wd_languages
local outputLanguages = {} -- {key = {label1, category1}, key = {label2, category2}}
local outputLanguage = function(label, category, note)
return {label = label, category = category, note = note or '' }
end
if wd_languages then
for i, language in pairs(wd_languages) do
local languageId = statementQID(language)
if languageId then
language = conf.language[languageId]
outputLanguages[languageId] = outputLanguage(
shortWikidataLabel(languageId),
language and p._languageCategory(language, is_free)
)
improved = true
end
end
if nszero then
if improved then
if tl_has then
-- Wikidata at megioradu su template e su template teniat giai àteros valores
s = s .. '[[Categoria:P277 diferente in Wikidata]]'
else
-- Wikidata at megioradu su template chi fiat bòidu
s = s .. '[[Categoria:P277 lèghida dae Wikidata]]'
end
else
if p._templateHasExtraInformations(args) or count(tl_languages) > count(wd_languages) then
-- In su template b'at carchi cosa de prus cunfronta a Wikidata
s = s .. '[[Categoria:P277 diferente in Wikidata]]'
elseif count(wd_languages) ~= 0 then
-- No at megioradu nudda ca sunt sos matessi valores
s = s .. '[[Categoria:P277 uguale in Wikidata]]'
end
end
end
else
if tl_has and nszero then
-- petzi si su template ispetzìficat limbàgios ma Wikidata nono
s = s .. '[[Categoria:P277 chi mancat in Wikidata]]'
end
end
if tl_languages then
for languageSlug, note in pairs(tl_languages) do
if languageSlug == 'disconnotu' then
outputLanguages[languageSlug] = outputLanguage(
"Disconnotu",
TEMPLATE_UNKNOWN_ARG_CAT,
note
)
else
local languageId = conf.languageSlugToWikidata[languageSlug]
local language = conf.language[languageId]
if language then
outputLanguages[languageId] = outputLanguage(
shortWikidataLabel(languageId),
p._languageCategory(language, is_free),
note
)
else
-- Ammustra·la su matessi, a casu, tantu pro lu fàghere
outputLanguages[languageSlug] = outputLanguage(
languageSlug,
p._languageCategory(languageSlug, is_free),
note
)
tl_allFound = false
end
end
end
end
local i = 0
for id, language in pairs(outputLanguages) do
local glue = i > 0 and '<br />' or ''
s = s .. glue .. language.label .. language.note .. (categorize and language.category or '')
i = i + 1
end
if args['LimbàgiuÀteros'] then
local glue = i > 0 and '<br />' or ''
s = s .. glue .. args['LimbàgiuÀteros']
end
if nszero then
if not tl_allFound then
s = s .. TEMPLATE_UNKNOWN_ARG_WARN .. TEMPLATE_UNKNOWN_ARG_CAT
end
if not wd_allFound then
s = s .. UNKNOWN_WD_LANGUAGE
end
if noLanguages and is_free then
s = s .. FREE_WITHOUT_LANGUAGE
end
end
return s
end
function p.manLanguages(frame)
local s = '<table class="wikitable"><tr><th>Parametro</th><th>Risultato</th><th>Categoria automatica</th></tr>'
local TD = '<td>%s</td>'
for id, language in pairs( conf.language ) do
s = s .. '<tr>'
local slugs, i = '', 0
for slug, sub_id in pairs( conf.languageSlugToWikidata ) do
if sub_id == id then
local glue = i > 0 and '<br />' or ''
slug = "<code>" .. slug .. "</code>"
slugs = slugs .. glue .. slug
i = i + 1
end
end
s = s .. string.format(TD, slugs)
s = s .. string.format(TD, shortWikidataLabel(id) )
s = s .. string.format(TD, p._languageCategory(language, nil, true, '//') )
s = s .. '</tr>'
end
return s .. '</table>'
end
-------------------------------- Fine ---------------------------------------
--[[
* Categorizare?
*
* @return true|false
]]
function p._categorize(args)
local v = args['Categorias']
if v then
return mw.ustring.lower(v) ~= 'nono'
end
return true
end
--[[
* Faghimus unu resumu. S'artìculu est de unu programma lìberu?
*
* @return true|false|nil
]]
function p._isFreeSoftware(args)
local is_wd = p._isFreeSoftwareByWikidata()
local isnt_wd = p._isProprietarySoftwareByWikidata()
local is_tp = p._isFreeSoftwareByTemplate(args)
local is = nil
if is_wd then
is = true
end
if isnt_wd then
is = false
end
if is_tp ~= nil then
is = is_tp
end
--if is_wd == true and isnt_wd == true then
-- Wikidata nonsense
--end
--if is_wd == true and is_tp == true then
-- Local same as Wikidata
--
--if (is_wd == true and is_tp == false) or (isnt_wd == true and is_tp == false) then
-- Free different from Wikidata
--
--if (is_wd ~= nil or isnt_wd ~= nil) and is_tp == false then
-- Free/proprietary read from Wikidata
--
return is
end
--[[
* Fatu-fatu s'artìculu est definidu in Wikidata che a istàntzia de programma lìberu.
* Pro su chi pertocat a Wikipedia est discansosu.
* Pro su chi pertocat a Wikidata si ripetit cun su campu litzèntzia P275.
*
* @param string from Wikidata item
* @return true|false
]]
function p._isFreeSoftwareByWikidata(from)
-- Q341 free software
-- Q1130645 open-source software
return mWikidata._instanceOf({'Q341', 'Q1130645', from = from}) or p._hasAFreeLicense(from)
end
--[[
* Fatu-fatu s'artìculu est definidu in Wikidata che a istàntzia de programma propietàriu.
* Pro su chi pertocat a Wikipedia est discansosu.
* Pro su chi pertocat a Wikidata si ripetit cun su campu litzèntzia P275.
*
* @param from string Wikidata item
* @return true|false
]]
function p._isProprietarySoftwareByWikidata(from)
-- Q218616 proprietary software
-- Q178285 freeware TODO: impròpia, subclass of anteposta
return mWikidata._instanceOf({'Q218616', 'Q178285', from = from}) or p._hasAProprietaryLicense(from)
end
--[[
* Leghidura banale de `ProgrammaLìberu = eja/nono` in su template {{Programma}}
*
* @return nil|true|false
--]]
function p._isFreeSoftwareByTemplate(args)
local is = nil
local v = args['ProgrammaLìberu']
if v then
local yep = {['eja'] = true, ['emmo'] = true, ['no'] = false, ['nono'] = false}
v = yep[ mw.ustring.lower(v) ]
end
return v
end
--[[
* Riassumendo. La voce dovrebbe specificare un linguaggio?
*
* @return true|nil
]]
function p._shouldHaveALanguage(args)
return p._isFreeSoftware(args) or p._specifiesALanguage(args)
end
--[[
* B'at unu limbàgiu?
*
* @return truly|nil
]]
function p._specifiesALanguage(args)
return p._templateHasLanguages(args) or mWikidata._N({ 'P277' }) > 0
end
--[[
* Il template ha il campo "Linguaggio"?
*
* @return truly|nil
]]
function p._templateHasLanguages(args)
return args['Limbàgiu'] or args['NotaLimbàgiu'] or args['LimbàgiuÀteros']
end
--[[
* Su template tenet valores chi non si podent unire a Wikidata?
*
* @return truly|nil
]]
function p._templateHasExtraInformations(args)
return args['LimbàgiuÀteros'] or args['NotaLimbàgiu'] or args['NotaLimbàgiu2'] or args['NotaLimbàgiu3']
end
--[[
* Pro mantènnere sa retrocumpatibilidade cun sa possibilidade de tènnere prus còdighes.
*
* Esèmpiu:
* 'cpp' → 'c++'
* 'c++' → 'c++'
*
* @param string
* @see Template:Software/Linguaggio
* @return string
]]
function p._preferredLanguageSlug(slug)
if slug then
slug = string.lower(slug)
end
return conf.languageSlugAlias[slug] or slug
end
--[[
* Sos còdighes de sos limbàgios in su template {{Programma}}.
*
* @return string[] = 'c' => 'nota limbàgiu c', 'c++' = '', ..
]]
function p._getTemplateLanguages(args)
local languages = {}
for i=0,3 do
local j = i == 0 and '' or i
local v = args['Limbàgiu' .. j]
if v then
v = p._preferredLanguageSlug(v)
languages[ v ] = args['NotaLimbàgiu' .. j] or ''
end
end
return languages
end
--[[
* Custa litzèntzia si podet identificare a manera direta?
*
* @TODO: Torrare a iscrìere in carchi manera prus umana.
*
* @param license string Wikidata item
* @return FREE|PROPRIETARY|UNKNOWN
]]
function p._singleLicenseType(license)
-- Q1156659 OSI-approved license
-- Q5975031 free software copyleft license
-- Q3943414 free software license
-- Q31202214 proprietary software license
-- Q218616 proprietary software
-- Q3238057 proprietary license!
--[[
* Istùdios aprofundidos dae puntos de vista non neutrales ant evidentziados comente
* sas tres rigas chi sighint siant s'*ùnica* parte piaghile de su Lua.
]]
return (license == 'Q3943414' or license == 'Q5975031' or license == 'Q1156659') and FREE
or (license == 'Q31202214' or license == 'Q218616' or license == 'Q3238057') and PROPRIETARY
or UNKNOWN
end
--[[
* Intre custas litzèntzias b'at una classe raighina chi faghet a identificare?
*
* @param license string Wikidata item
* @return FREE|PROPRIETARY|UNKNOWN
* ]]
function p._findLicenseType(licenses)
local type = UNKNOWN
for _, license in pairs(licenses) do
type = p._singleLicenseType(license)
if type ~= UNKNOWN then
break
end
end
return type
end
--[[
* Otenet sa tipologia de una litzèntzia de programmas cale si siat.
*
* Una litzèntzia si podet identificare gràtzias a Wikidata iscurrende in manera ricursiva
* s'àrbore de litzèntzias mamas finas a arribbare a una classe de raighina chi si podet identificare.
*
* Custu podet pàrrere assustadore, ma in beridade paret bastente efitziente,
* batinde s'impreu mèdiu de funtziones parser gastosas a +2/+3.
*
* In cada anera su lìmite de sas funtziones parser gastosas est 500,
* mentras si ipotizat chi custa funtzione nde potzat provocare a su màssimu +5/+6
* pro sos pègiu casos.
*
* @param license string Wikidata item
* @param i int|nil Livellu de
* @see Module:Programma/man#Cunsideros implementativos
* @return UNKNOWN|FREE|PROPRIETARY
]]
local _licenseType_ = {} --cache
function p._licenseType(license, i)
i = i or 0
if _licenseType_[license] == nil then
-- Est una liztèntzia raighina?
local type = p._singleLicenseType(license)
local license_instances = {}
if type == UNKNOWN then
-- In `istance of` b'at una litzèntzia de raighina?
license_instances = rawProperties(license, 'P31')
if license_instances then
type = p._findLicenseType(license_instances)
end
end
local license_classes = {}
if type == UNKNOWN then
-- In `subclass of` b'at una litzèntzia de raighina?
license_classes = rawProperties(license, 'P279')
if license_classes then
type = p._findLicenseType(license_classes)
end
end
if i <= MAX_RECURSION then
-- Bae a `istance of`
if type == UNKNOWN then
if license_instances then
for _, license_instance in pairs(license_instances) do
type = p._licenseType(license_instance, i + 1)
if type ~= UNKNOWN then
break
end
end
end
end
-- Bae a `subclass of`
if type == UNKNOWN then
if type == UNKNOWN and license_classes then
for _, license_class in pairs(license_classes) do
type = p._licenseType(license_class, i + 1)
if type ~= UNKNOWN then
break
end
end
end
end
-- Non b'at àteru pro s'abbrancare
end
_licenseType_[license] = type
end
return _licenseType_[license]
end
--[[
* Litzèntzias dae Wikidata.
*
* @param from string|nil Wikidata item
* @return table|nil
]]
local _licenses_cache = false
function p._licenses(from)
if _licenses_cache == false then
_licenses_cache = mWikidata._getClaims('P275', {from = from}) or {}
end
return _licenses_cache
end
--[[
* Tenet una tzerta casta de litzèntzia?
*
* Pro resones de rendimentu dae su 29 de trìulas de su 2017 si chircat petzi finas a sa prima litzèntzia chi faghet a identificare.
*
* @param type FREE|PROPRIETARY|UNKNOWN
* @param from string|nil Wikidata item
* @return true|false
]]
function p._hasALicenseOfType(type, from)
for _, l in pairs( p._licenses(from) ) do
l = statementQID(l)
if l then
local retrievedType = p._licenseType(l)
if type ~= UNKNOWN then
return type == retrievedType
end
end
end
return false
end
--[[
* S'artìculu est suta de litzèntzia de programma lìberu Wikidata?
*
* @param from string|nil Wikidata item
* @return true|false
]]
function p._hasAFreeLicense(from)
return p._hasALicenseOfType(FREE, from)
end
--[[
* S'artìculu est suta de litzèntzia de programma propietàriu in Wikidata?
*
* @param from string|nil Wikidata item
* @return true|false
]]
function p._hasAProprietaryLicense(from)
return p._hasALicenseOfType(PROPRIETARY, from)
end
--[[
* Categorias ligadas a sas litzèntzias dae Wikidata.
*
* @param from string|nil Wikidata Item
* @return string
]]
function p._licenseCategories(from)
local s = ''
for i, l in pairs( p._licenses( from ) ) do
local id = statementQID( l ) -- can be nil but don't care
local name = conf.licenseCategory[ id ]
if name then
local cat = conf.licenseCategoryShorter[id] and LICENSE_CAT_SHORTER or LICENSE_CAT
s = s .. formatCategory(cat, name)
else
s = s .. UNKNOWN_WD_LICENSE
end
end
return s
end
--[[
* Categorias ligadas a sos limbàgios dae Wikidata.
*
* @param from string|nil Wikidata Item
* @return string
]]
function p._languageCategories(from)
local s = ''
local languages = mWikidata._getClaims('P277', {from = from} ) -- Property:programming language
local free = p._isFreeSoftwareByWikidata(from)
local missing = false
if languages then
for _, l in pairs( languages ) do
l = conf.language[ statementQID(l) ]
if l then
s = s .. p._languageCategory(l, free)
else
missing = true
end
end
elseif free then
s = FREE_WITHOUT_LANGUAGE
end
if missing then
s = s .. UNKNOWN_WD_LANGUAGE
end
return s
end
--[[
* Categorias ligadas a sos toolkits o frameworks de s'interfache gràfica dae Wikidata.
*
* @param from string|nil Wikidata Item
* @return string
]]
function p._toolkitCategories(from)
local s = ''
local toolkits = mWikidata._getClaims('P1414', {from = from} ) -- Property:GUI toolkit or framework
local free = p._isFreeSoftwareByWikidata(from)
local missing = false
if toolkits then
for _, t in pairs( toolkits ) do
t = conf.language[ statementQID( t ) ] -- the ID can be nil but don't care
if t then
s = s .. p._languageCategory(t, free)
else
missing = true
end
end
end
if missing then
s = s .. UNKNOWN_WD_TOOLKIT
end
return s
end
--[[
* Sa categoria de unu limbàgiu ispetzìficu de programmatzione.
* A nàrrere sa beridade custa categorizatzione est anàloga fintzas pro sos toolkits.
*
* @param language table
* @param free boolean|nil Est unu programma lìberu?
* @param man boolean|nil Tenet una punna de documentatzione?
* @param deefault string|nil Valore predefinidu s'in casu manchet
* @see Module:Programma/Cunfiguratzione
* @return string
]]
function p._languageCategory(lang, free, man, default)
local s
if lang.cat then
s = free and lang.free and "Programma lìberu in %s" --free = true
or free == false and lang.nonfree and "Programma propietàriu in %s" --free = false
or "Programma in %s" --free = nil
s = formatCategory(s, lang.cat, man)
end
return s or default or ''
end
--[[
* Categoria ligada a sa data de fundatzione.
* @todo Cumprèndere cale depet tènnere sa pretzedèntzia intre sa data de publicatzione e sa data de creatzione
* @param from string|nil Wikidata Item
* @param value string|nil Local value
* @return string
]]
function p._yearsCategories(from, value)
local mCategoryByYear = require('Module:Categoria pro annu')._main
local creation = mCategoryByYear( { YEAR_CAT, from = from, value = value, raw = true } )
if '' == creation then
return mCategoryByYear( { YEAR_CAT, from = from, value = value, prop = 'P577', checkCat = 'Data de publicatzione', checkGenre = 'fs' } )
end
return mCategoryByYear( { YEAR_CAT, from = from, value = value } )
end
return p