Module:Lingua Libre record
Jump to navigation
Jump to search
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
This module powers {{Lingua Libre record}}. It exports two functions, both of which mainly read their parameters from the parent frame (i.e. the place that transcluded {{Lingua Libre record}}). The functions are:
- main
- Returns the wikitext content of the template, mainly an {{Information}} block. Takes the same parameters as the template, plus one additional argument: if
|includeonly=y
, then categories are included in the result (by default, they are not included). The template uses|includeonly=<includeonly>y</includeonly>
to only set this parameter when the template is being transcluded; this effectively does the same thing that<includeonly>[[Category:...]]</includeonly>
would do in a non-Lua-based template. - defaultsort
- Returns the defaultsort string for the page. This has to be a separate function because the
{{DEFAULTSORT:}}
magic word can’t be in the wikitext returned bymain
. Takes the same parameters as the template (but doesn’t use all of them).
Code
local p = {}
local delink = nil -- lazy-loaded from require( 'Module:Delink' ).delink
local langSwitch = nil -- lazy-loaded from require( 'Module:LangSwitch' )._langSwitch
local getLabel = nil -- lazy-loaded from require( 'Module:Wikidata label' )._getLabel
local downloadLink = '[[File:Crystal Clear app download manager.svg|12px|link=lingualibre:Help:Download datasets]]'
local messages = mw.loadData( 'Module:Lingua Libre record/i18n' )
local _lang = nil -- lazy-loaded from {{int:lang}}
-- Get the user interface language code.
local function lang( frame )
if _lang == nil then -- lazy-load
_lang = frame:callParserFunction( 'int', 'lang' )
end
return _lang
end
-- Get the localized version of the message with the given key from the /i18n module.
local function message( frame, key )
if langSwitch == nil then -- lazy-load
langSwitch = require( 'Module:LangSwitch' )._langSwitch
end
local msg = langSwitch( messages[ key ], lang( frame ) )
if msg == '' then
msg = frame:expandTemplate{
title = 'Please translate',
args = {
messages[ key ].en,
'Module:Lingua Libre record',
demo = 'yes',
},
}
end
return msg
end
-- Get the first best-rank data value (skipping somevalue/novalue)
-- for the given property ID from the given entity, or nil.
-- Used by bestStringValue, bestEntityIdValue, bestMonolingualTextValue.
local function bestDataValue( entity, propertyId )
if not entity then return nil end
local statements = entity:getBestStatements( propertyId )
for i = 1, #statements do
local snak = statements[ i ].mainsnak
if snak.snaktype == 'value' then
return snak.datavalue
end
end
return nil
end
-- Get the first best-rank string value (skipping somevalue/novalue)
-- for the given property ID from the given entity, or nil.
local function bestStringValue( entity, propertyId )
local value = bestDataValue( entity, propertyId )
if not value then return nil end
assert( value.type == 'string', 'data value type of ' .. propertyId .. ' must be string, not ' .. value.type )
return value.value
end
-- Get the first best-rank entity ID value (skipping somevalue/novalue)
-- for the given property ID from the given entity, or nil.
local function bestEntityIdValue( entity, propertyId )
local value = bestDataValue( entity, propertyId )
if not value then return nil end
assert( value.type == 'wikibase-entityid', 'data value type of ' .. propertyId .. ' must be wikibase-entityid, not ' .. value.type )
return value.value.id
end
-- Get the first best-rank monolingual text value (skipping somevalue/novalue)
-- for the given property ID from the given entity, or nil.
-- Returns wikitext (string), the plain value (string), and its language (object).
local function bestMonolingualTextValue( entity, propertyId )
local value = bestDataValue( entity, propertyId )
if not value then return nil end
assert( value.type == 'monolingualtext', 'data value type of ' .. propertyId .. ' must be monolingualtext, not ' .. value.type )
local text = value.value.text
local language = mw.language.new( value.value.language )
local span = mw.html.create( 'span' )
span
:attr( 'lang', language:getCode() )
:attr( 'dir', language:getDir() )
:wikitext( mw.text.nowiki( text ) )
return tostring( span ), text, language
end
-- Get the first best-rank time value (skipping somevalue/novalue)
-- for the given property ID from the given entity, or nil.
-- Requires proleptic Gregorian calendar,
-- and automatically removes irrelevant parts of the timestamp according to the precision.
local function bestTimeValue( entity, propertyId )
local value = bestDataValue( entity, propertyId )
if not value then return nil end
assert( value.type == 'time', 'data value type of ' .. propertyId .. ' must be time, not ' .. value.type )
if value.value.calendarmodel ~= 'http://www.wikidata.org/entity/Q1985727' then -- proleptic Gregorian calendar
return nil
end
local timestamp = value.value.time
local precision = value.value.precision
local pattern = '^+?((((((-?%d*)-%d*)-%d*)T%d*):%d*):%d*)Z$'
local replacement = '%1' -- second
if precision == 13 then replacement = '%2' -- minute
elseif precision == 12 then replacement = '%3' -- hour
elseif precision == 11 then replacement = '%4' -- day
elseif precision == 10 then replacement = '%5' -- month
elseif precision <= 9 then replacement = '%6' -- year
end
return mw.ustring.gsub( timestamp, pattern, replacement )
end
-- Get the first Wikimedia username (P4174) qualifier
-- of the first best recordist (P10893) statement, or nil.
local function bestAuthor( entity )
if not entity then return nil end
local statements = entity:getBestStatements( 'P10893' )
for i = 1, #statements do
local qualifiers = statements[ i ].qualifiers or {}
for j = 1, #( qualifiers.P4174 or {} ) do
local qualifier = qualifiers.P4174[ j ]
if qualifier.snaktype == 'value' then
local userName = qualifier.datavalue.value
return '[[User:' .. userName .. '|' .. userName .. ']]'
end
end
end
return nil
end
-- Get the first author name string (P2093) and Lingua Libre ID (P10369)
-- qualifiers of the first best spoken by (P10894) statement, or nil.
local function bestSpeaker( entity )
if not entity then return nil end
local statements = entity:getBestStatements( 'P10894' )
local speaker, speakerId
for i = 1, #statements do
local qualifiers = statements[ i ].qualifiers or {}
for j = 1, #( qualifiers.P2093 or {} ) do
local qualifier = qualifiers.P2093[ j ]
if qualifier.snaktype == 'value' then
speaker = qualifier.datavalue.value
break
end
end
for j = 1, #( qualifiers.P10369 or {} ) do
local qualifier = qualifiers.P10369[ j ]
if qualifier.snaktype == 'value' then
speakerId = qualifier.datavalue.value
break
end
end
end
return speaker, speakerId
end
-- Construct the {{Information}} template for the given information.
-- The parameters are used as they are: fallback to entity data is up to the caller.
local function information(
frame,
languageId,
transcriptionWikitext,
qualifier,
speaker,
speakerId,
author,
linguaLibreId,
date,
otherVersions
)
local wordSeparator = mw.message.new( 'word-separator' ):plain()
local languageField = ''
if languageId then
if getLabel == nil then
getLabel = require( 'Module:Wikidata label' )._getLabel
end
local languageLabel = getLabel( languageId, lang( frame ) )
languageField = frame:expandTemplate{ title = 'Information field', args = {
name = message( frame, 'language' ),
value = languageLabel .. wordSeparator .. downloadLink,
} }
end
local transcriptionField = ''
if transcriptionWikitext then
transcriptionField = frame:expandTemplate{ title = 'Information field', args = {
name = message( frame, 'transcription' ),
value = transcriptionWikitext,
} }
end
local qualifierField = ''
if qualifier and qualifier ~= '' then
qualifierField = frame:expandTemplate{ title = 'Information field', args = {
name = message( frame, 'qualifier' ),
value = qualifier,
} }
end
local speakerLink
if speaker and speaker ~= '' and speakerId and speakerId ~= '' then
speakerLink = '[[lingualibre:' .. speakerId .. '|' .. speaker .. ']]'
elseif speaker and speaker ~= '' then
speakerLink = speaker
elseif speakerId and speakerId ~= '' then
speakerLink = '[[lingualibre:' .. speakerId .. '|' .. speakerId .. ']]'
else
speakerLink = nil
end
local speakerItem = ''
if speakerLink then
speakerItem = '\n* ' .. message( frame, 'speaker' ) .. wordSeparator .. speakerLink
end
local recorderItem = ''
if author and author ~= '' then
recorderItem = '\n* ' .. message( frame, 'recorder' ) .. wordSeparator .. author
end
local source = frame:expandTemplate{ title = 'Own' }
if linguaLibreId then
local linguaLibreLabel = mw.wikibase.getLabel( 'Q60024037' )
local linguaLibreLink = '[[lingualibre:' .. linguaLibreId .. '|' .. linguaLibreLabel .. ']]'
source = source .. wordSeparator .. mw.message.new( 'parentheses', linguaLibreLink ):plain()
end
return frame:expandTemplate{ title = 'Information', args = {
Description = message( frame, 'description' ),
other_fields_1 = languageField .. transcriptionField .. qualifierField,
Author = speakerItem .. recorderItem,
Source = source,
Date = date,
[ 'Other versions' ] = otherVersions,
} }
end
-- Construct the categories for the given information.
local function categories( languageId, speaker, speakerId, author, date )
local languageCategory
if languageId and languageId ~= '' then
local languageCode = bestStringValue( mw.wikibase.getEntity( languageId ), 'P220' )
if languageCode then
languageCategory = '[[Category:Lingua Libre pronunciation-' .. languageCode .. ']]'
else
languageCategory = '[[Category:Lingua Libre pronunciation-other (' .. languageId .. ')]]'
end
else
languageCategory = '[[Category:Lingua Libre pronunciation with incomplete parameters]]'
end
local authorCategory = ''
if author and author ~= '' then
if delink == nil then -- lazy-load
delink = require( 'Module:Delink' ).delink
end
local authorCategoryTitle = 'Category:Lingua Libre pronunciation by ' .. delink( { author } )
if mw.title.new( authorCategoryTitle ).exists then
authorCategory = '[[' .. authorCategoryTitle .. ']]'
end
else
authorCategory = '[[Category:Lingua Libre pronunciation with incomplete parameters]]'
end
local speakerCategory = ''
if not ( speaker and speaker ~= '' and speakerId and speakerId ~= '' ) then
speakerCategory = '[[Category:Lingua Libre pronunciation with incomplete parameters]]'
end
local dateCategory = ''
if not ( date and date ~= '' ) then
dateCategory = '[[Category:Lingua Libre pronunciation with incomplete paremeters]]'
end
return languageCategory .. authorCategory .. speakerCategory
end
-- Parse the arguments out of the given frame,
-- including fallbacks to the parent frame and to entity data.
local function parseArgs( frame )
local args = frame.args
local pargs = frame:getParent().args
local speaker = args.locutor or args.speaker or pargs.locutor or pargs.speaker
local speakerId = args.locutorId or args.speakerId or pargs.locutorId or pargs.speakerId
local author = args.author or pargs.author
local languageId = args.languageId or pargs.languageId
local transcriptionWikitext = args.transcription or pargs.transcription
local qualifier = args.qualifier or pargs.qualifier
local date = args.date or pargs.date
local otherVersions = args['other versions'] or pargs['other versions']
local mid = args.mid or pargs.mid
local entity
if mid then
entity = mw.wikibase.getEntity( mid )
else
entity = mw.wikibase.getEntity()
end
local linguaLibreId = bestStringValue( entity, 'P10369' )
if ( not speaker or speaker == '' ) and ( not speakerId or speakerId == '' ) then
speaker, speakerId = bestSpeaker( entity )
end
if not author or author == '' then
author = bestAuthor( entity )
end
if not languageId or languageId == '' then
languageId = bestEntityIdValue( entity, 'P407' )
end
local transcription = transcriptionWikitext
if not transcriptionWikitext or transcriptionWikitext == '' then
transcriptionWikitext, transcription = bestMonolingualTextValue( entity, 'P9533' )
end
if not date or date == '' then
date = bestTimeValue( entity, 'P10135' )
end
return speaker, speakerId, author, languageId, transcriptionWikitext, transcription, qualifier, date, otherVersions, linguaLibreId
end
-- Main function, returning most of the relevant wikitext.
-- {{DEFAULTSORT:}} cannot be done here, callers must also invoke the defaultsort function below.
function p.main( frame )
local speaker, speakerId, author, languageId, transcriptionWikitext, transcription, qualifier, date, otherVersions, linguaLibreId = parseArgs( frame )
local includeonly = frame.args.includeonly == 'y'
local info = information(
frame,
languageId,
transcriptionWikitext,
qualifier,
speaker,
speakerId,
author,
linguaLibreId,
date,
otherVersions
)
local cats = ''
if includeonly then
cats = categories( languageId, speaker, speakerId, author, date )
end
return '<div class="haudio">' .. info .. '</div>' .. cats
end
-- Return the {{DEFAULTSORT:}} string that should be used.
-- The {{DEFAULTSORT:}} magic word itself must be in the invoking wikitext.
function p.defaultsort( frame )
local speaker, speakerId, author, languageId, transcriptionWikitext, transcription, qualifier, date, otherVersions, linguaLibreId = parseArgs( frame )
if transcription and transcription ~= '' then
local suffix = ''
if qualifier and qualifier ~= '' then
suffix = ' ' .. qualifier
end
return transcription .. suffix
else
return ''
end
end
return p