Modulo:Citazione

Modulo Lua per la riproduzione delle funzioni dei vari template {{Cita libro}}, {{Cita web}}, {{Cita news}}, {{Cita pubblicazione}}, {{Cita conferenza}} e {{Cita video}}.

Quelle che seguono sono note tecniche sul funzionamento del modulo. Per le istruzioni su come usarlo per inserire citazioni nelle voci vedi il manuale di {{Cita testo}}.

Sottomoduli

  • Modulo:Citazione/Configurazione - Contiene le tabelle di configurazione con i nomi dei parametri, i messaggi di errore, i caratteri di separazione...
  • Modulo:Citazione/Whitelist - Contiene le tabelle dei parametri accettati dal modulo per poter identificare parametri con un nome errato.
  • Modulo:Citazione/Suggerimenti - Contiene una tabella in cui è possibile inserire nomi di parametri che vengono sbagliati spesso e suggerire nel messaggio d'errore il nome del parametro corretto.
  • Modulo:Citazione/Argomenti - Serve a generare Modulo:Citazione/Whitelist ed è usato una tantum.

Funzioni accessorie

Nel seguito per settata si intende una variabile diversa da nil e da stringa nulla

is_set(var)
vera se una variabile è settata
first_set(...)
ritorna la prima variabile settata
inArray( needle, haystack )
scandisce l'array haystack e ritorna la posizione in cui si trova il valore needle. Se needle non si trova in haystack o è nil ritorna false
substitute( msg, args )
ritorna la stringa msg compilata usando la tabella di valori args. Basata sulla funzione mw.message.newRawMessage, non granchè documentata, apparentemente nella stringa i $n vengono sostituiti dal valore in posizione ennesima in args. Se args è nil ritorna nil
wrap( key, str, lower )
formatta il messaggio key con la stringa str. key deve essere un indice della tabella citation_config.messages. Se lower è vero il messaggio viene messo in minuscolo prima di inserire str
debug_msg(msg)
inserisce un messaggio di debug nella coda dei messaggi di errore per essere emesso a video
debug_value(name, value)
inserisce il messaggio di debug name = value. Usata per emettere il valore di una variabile, da usare per esempio come debug_value('name', name)
argument_wrapper( args )
restituisce una tabella per accedere ai valori della tabella originale args mediante una tabella di alias. Data l'istruzione A=argument_wrapper(args) la chiamata A[key] il valore args[first_set(citation_config.aliases[key])]. Questo permette la localizzazione dei parametri e la creazione di alias per lo stesso valore. Per esempio se citation_config.aliases['Chapter'] = {'capitolo', 'contributo', 'voce', 'articolo', 'sezione' } la chiamata A['Chapter'] resituirà uno dei valori settati tra args['capitolo'], args['contributo'], args['voce'], args['articolo'], args['sezione']. Aggiunge inoltre il metodo A:ORIGIN che restituisce l'alias con il quale è stato trovato un valore. I valori trovati vengono bufferizzati in una tabella interna.
Aggiunge un messaggio alla coda di errori se:
  • key non è presente in citation_config.aliases
  • key è una tabella di valori e più di uno di questi è settato
  • se in args non viene trovato alcun valore corrispondente a uno degli alias di key ritorna stringa vuota ""
validate(name)
ritorna true se name non è nil ed è il nome di un parametro accettato, false in caso contrario
errorcomment( content, hidden )
formatta il commento comment per la visualizzazione, se hidden è true il codice sarà inserito ma non visibile salvo analizzare il codice html della pagina, altrimenti sarà formattato come da settaggio delle classi "error" e "citation-comment" nel css (normalmente una scritta in rosso)
seterror( error_id, arguments, raw, prefix, suffix )
formatta il commento con codice error_id con la tabella di argomenti arguments. Se valorizzati prefix e suffix vengono aggiunti rispettivamente prima e dopo il messggio. Se raw è true il messaggio viene ritornato senza essere passato prima per errorcomment.
la chiave error_id fa riferimento alla tabella di messaggi citation_config.error_conditions che per ogni codice di errore restituisce il messaggio da formattare, la categoria di errore in cui inserire la voce e se il messaggio deve essere visibile o nascosto.

Fragment

Per gestire l'unione dei pezzi di citazione, viene definito un "oggetto" Lua (in realtà una tabella con una metatable che definisce alcuni metodi aggiuntivi). Un fragment è composto da un array il cui primo elemento è un stringa da inserire all'inizio della sequenza, seguito da uno o più stringhe e terminati da una stringa da inserire al termine della sequenza. Quando due frammenti f1 e f2 vengono uniti (vedi fragment.append e fragment.appends) viene valutata la priorità dell'ultimo separatore di f1 e quella del primo di f2 e conservato solo quello con priorità maggiore. Il nuovo frammento avrà il separatore iniziale di f1 e quello finale di f2.

Fragment.new(text, sep_key)
crea un pseudooggetto Lua che memorizza l'array di stringhe text usando come separatore tra una stringa e l'altra sep_key. Setta come separatore iniziale per la sequenza la stringa nulla e come separatore finale sep_key. Ritorna l'oggetto creato.
Sep_key deve essere una chiave della tabella Fragment.priority che per ogni separatore indica la sua priorità (quindi quale separatore prevale quando due frammenti vengono uniti) e cosa inserire esattamente (per esempio per "," inserisce in realtà ", " — aggiunge cioè lo spazio). La tabella è caricata dal modulo di configurazione, un esempio è:
[""] = { order=0, sep = ""},
[" "] = { order=1, sep = " "},
[","] = { order=2, sep = ", "},
["."] = { order=3, sep = ". "},
["in"] = {order=4, sep = " in "},
[" "] = { order=5, sep = " "}, spazio semplice che però prevale su altri separatori
["nothing"] = {order=6, sep="" } stringa nulla che prevale su tutto (per forzare nessun separatore a inizio citazione)
Fragment:start(sep_key)
setta come separatore iniziale sep_key
Fragment:last(sep_key)
setta come separatore finale sep_key
Fragment:empy(sep_key)
ritorna true se fragment è un frammento vuoto (contiene un array di stringhe vuoto)
Fragment:append(txr)
appende il frammento o strigna txr in fondo a fragment (nel caso che txr è una stringa la trasforma in fragment con sep_key uguale a quella del frammento a cui viene appesa)
Fragment:appends(txr)
appende un array misto di frammenti/stringhe

-- Modulo per la gestione delle citazioni, originariamente importato dalla-- revisione 555909894 del 20/5/2013 da [[:en:Module:Citation/CS1]]--[[ ===============================================================================Variabile in cui vengono memorizzate le condizioni di errore registrate durante l'esecuzionedelle funzioni del modulo.===============================================================================]]local z = {error_categories = {}; -- lista delle categorie di erroreerror_ids = {}; -- lista dei codici di erroremessage_tail = {}; -- messaggi di errore da visualizzare in coda alla citazione}--[[ ===============================================================================Carica la tabella di configurazione, correggendo il nome se caricato da sandbox-- nota: non ancora attiva per qualche motivo non funziona===============================================================================]]local function load_configuration_table(name)local frame = mw.getCurrentFrame()local real_name = nameif nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then   real_name = real_name .. '/sandbox'endreturn  mw.loadData(real_name)end--[[ ===============================================================================Caricamento delle tabelle di configurazione del modulo.===============================================================================]]local cfg = mw.loadData('Module:Citazione/Configurazione')--local cfg = load_configuration_table('Module:Citazione/Configurazione')--[[ ===============================================================================Lista di tutti i parametri riconosciuti.===============================================================================]]local whitelist = mw.loadData('Module:Citazione/Whitelist')--local whitelist = load_configuration_table('Module:Citazione/Whitelist')--[[ ===============================================================================Ritorna true se una variabile è settata (diversa da nil e da stringa vuota)===============================================================================]]local function is_set( var )return not (var == nil or var == '');end-- Ritorna il nostro {{Collegamento interrotto}}local function interrupted_url()return mw.getCurrentFrame():expandTemplate{ title = 'Collegamento interrotto' }end--[[ ===============================================================================Ritorna la prima variabile settata di quelle passate alla funzione===============================================================================]]local function first_set(...)local list = {...};for _, var in pairs(list) doif is_set( var ) thenreturn var;endendend--[[ ===============================================================================Ritorna la posizione di needle nella lista haystack, altrimenti ritorna false===============================================================================]]local function in_array( needle, haystack )if needle == nil then return false; endfor n,v in ipairs( haystack ) doif v == needle then return n; endendreturn false;end--[[ ===============================================================================Popola gli argomenti numerati nella stringa msg usando la tabella di argomenti args===============================================================================]]local function substitute( msg, args )return args and mw.message.newRawMessage( msg, args ):plain() or msg;end--[[ ===============================================================================Rende la stringa sicura per il markup corsivo '' ... ''Nota: non si può usare <i> per il corsivo poichè il comportamento atteso se lo sispecifica per i titoli è di renderli non corsivi. Inoltre <i> e '' interagisconomale con la funzione HTML tidy di Mediawiki===============================================================================]]local function safe_for_italics( str )if not is_set(str) thenreturn str;elseif str:sub(1,1) == "'" then str = "<span></span>" .. str; endif str:sub(-1,-1) == "'" then str = str .. "<span></span>"; end-- Rimuove le andate a capo perché rompono il corsivo.return str:gsub( '\n', ' ' );endend--[[ ===============================================================================Ritorna true/false a seconda che la stringa si possa scrivere in corsivo===============================================================================]]local function is_italicizable( str )return require('Modulo:Valido in corsivo')._main({ str })end--[[ ===============================================================================Restituisce un messaggio dalla tabella cfg.messages in cui viene inserita una stringa- key: codice del messaggio da visualizzare in cfg.messages- str: una stringa da inserire nel messaggio, se non è definita o uguale a stringavuota la funzione ritorna una stringa vuota===============================================================================]]local function wrap( key, str )if not is_set( str ) thenreturn "";elseif in_array( key, { 'italic-title', 'trans-italic-title' } ) thenstr = safe_for_italics( str );endreturn substitute( cfg.messages[key], {str} );end--[[ ===============================================================================Inserisce un messaggio di debug da visualizzare in coda alla citazione===============================================================================]]local function debug_msg(msg)table.insert( z.message_tail, { set_error( 'debug_txt', {msg}, true ) } );end--[[ ===============================================================================A scopo di debug, aggiunge la stringa 'name=<value>' in coda alla citazione===============================================================================]]local function debug_value(name, value)if not value then value='nil' enddebug_msg(name .. '="'.. value .. '"')end--[[ ===============================================================================Formatta un commento per identificare gli errori, aggiungendo la classe css perrenderlo visibile o meno===============================================================================]]local function error_comment( content, hidden )return wrap( hidden and 'hidden-error' or 'visible-error', content );end--[[ ===============================================================================Imposta un condizione di errore e ritorna un messaggio appropriato. L'inserimentodel messaggio nell'output è di responsabilità della funzione chiamante-- -- error_id: codice dell'errore (una chiave valida per cfg.error_conditions)-- -- arguments: una lista di argomenti opzionali per la formattazione del messaggio-- -- raw: ritorna una coppia: {messaggio di errore, visibilità} invece del messaggio--       di errore formattato-- -- prefix: stringa da aggiungere in testa al messaggio-- -- suffix: stringa da aggiungere in coda al messaggio===============================================================================]]local function set_error( error_id, arguments, raw, prefix, suffix )local error_state = cfg.error_conditions[ error_id ];prefix = prefix or "";suffix = suffix or "";if error_state == nil thenerror( cfg.messages['undefined_error'] );elseif is_set( error_state.category ) thentable.insert( z.error_categories, error_state.category );endlocal message = substitute( error_state.message, arguments );message = mw.ustring.format('%s ([[%s#%s|%s]])',message, cfg.messages['help page link'], error_state.anchor,cfg.messages['help page label'])z.error_ids[ error_id ] = true;if in_array( error_id, { 'bare_url_missing_title', 'trans_missing_title' } )and z.error_ids['citation_missing_title'] thenreturn '', false;endmessage = table.concat({ prefix, message, suffix });if raw == true then return message, error_state.hidden endreturn error_comment( message, error_state.hidden );end--[[ ===============================================================================Cerca il primo parametro settato da una lista di parametri e genera un errore sepiù di un parametro è settato.Ritorna la coppia (value, selected) dove value è il valore del parametro trovato eselected il nome del parametro trovato===============================================================================]]local function select_one( args, possible, error_condition, index )local value = nil;local selected = '';local error_list = {};if index ~= nil then index = tostring(index); end-- Handle special case of "#" replaced by empty stringif index == '1' thenfor _, v in ipairs( possible ) dov = v:gsub( "#", "" );if is_set(args[v]) thenif value ~= nil and selected ~= v thentable.insert( error_list, wrap( 'parameter', v ) );elsevalue = args[v];selected = v;endendendendfor _, v in ipairs( possible ) doif index ~= nil thenv = v:gsub( "#", index );endif is_set(args[v]) thenif value ~= nil and selected ~= v thentable.insert( error_list, wrap( 'parameter', v ));elsevalue = args[v];selected = v;endendendif #error_list > 0 then-- genera il messaggio di errore concatenando i parametri duplicatilocal error_str = "";if #error_list == 1 thenerror_str = error_list[1] .. cfg.messages['parameter-pair-separator'];elseerror_str = table.concat(error_list, cfg.messages['parameter-separator']) .. cfg.messages['parameter-final-separator'];enderror_str = error_str .. wrap( 'parameter', selected );table.insert( z.message_tail, { set_error( error_condition, {error_str}, true ) } );endreturn value, selected;end--[[ ===============================================================================Funzione di supporto per la mappatura degli argomenti del file di configurazione,così che nomi multipli possono essere assegnati ad una singola variabile interna===============================================================================]]local function argument_wrapper( args )local origin = {};return setmetatable({ORIGIN = function( self, k )local dummy = self[k]; --force the variable to be loaded.return origin[k];end},{__index = function ( tbl, k )if origin[k] ~= nil thenreturn nil;endlocal args, list, v = args, cfg.aliases[k];if type( list ) == 'table' thenv, origin[k] = select_one( args, list, 'redundant_parameters' );if origin[k] == nil thenorigin[k] = ''; -- Empty string, not nilendelseif list ~= nil thenv, origin[k] = args[list], list;else-- maybe let through instead of raising an error?-- v, origin[k] = args[k], k;error( cfg.messages['unknown_argument_map'] );end-- Empty strings, not nil;if v == nil thenv = cfg.defaults[k] or '';origin[k] = '';endtbl = rawset( tbl, k, v );return v;end,});end--[[ ===============================================================================Controlla che il nome di un parametro sia valido usando la whitelist===============================================================================]]local function validate( name )name = tostring( name );-- Normal argumentsif whitelist.basic_arguments[ name ] then return true end-- Arguments with numbers in themname = name:gsub( "%d+", "#" );if whitelist.numbered_arguments[ name ] then return true end-- Not found, argument not supported.return falseend--[[ ===============================================================================Oggetto per memorizzare gli elementi di una citazione. Un frammento di citazione èformato dai seguenti elementi:- self[n]: n-esimo elemento da unire, è una lista di stringhe inframezzata daiseparatori da usare per unirle.- self.last_priority: priorità del separatore di chiusura- self.first_priority: priorità del separatore di apertura- self.sep_key: codice del carattere separatore di default da usarese unita a un altro frammento   ===============================================================================]]local Fragment = {}Fragment.precedence = cfg.style.separator_prioritylocal Fragment_mt = { __index = Fragment }Fragment.new = function(texts, sep_key)if type(texts) == "string" then texts = { texts } endif not Fragment.precedence[sep_key] then sep_key = "" endlocal tx = { }tx.last_priority = 0tx.first_priority = 0tx.sep_key = sep_keytx[1] = ""for _, el in ipairs(texts) doif el ~= "" thentx[#tx+1] = eltx[#tx+1] = Fragment.precedence[tx.sep_key].sependendif #tx > 1 thentx.last_priority = Fragment.precedence[tx.sep_key].orderelsetx[1] = ""endsetmetatable(tx, Fragment_mt)return txend--- cambia il separatore iniziale di un frammento di citazionefunction Fragment:start(sep_key)if #self == 0 then return self endlocal separator = Fragment.precedence[sep_key] or Fragment.precedence[""]self[1] = separator.sepself.first_priority = separator.orderreturn selfend-- cambia il separatore finale di un frammento di citazionefunction Fragment:last(sep_key)if #self == 0 then return self endlocal separator = Fragment.precedence[sep_key] or Fragment.precedence[""]self[#self] = separator.sepself.last_priority = separator.orderreturn selfend-- ritorna un frammento di citazione vuotofunction Fragment:empty()return #self==0end-- appende una stringa o un frammento di citazione in codafunction Fragment:append(txr)if txr == nil then return self endif type(txr) == "string" then txr = Fragment.new(txr, self.sep_key) endif #txr == 0 then return self endif #self == 0 then self[1] = txr[1] endself.last_priority = self.last_priority or 0if self.last_priority < txr.first_priority thenself[#self] = txr[1]endfor i, el in ipairs(txr) doif i>1 then self[#self+1] = el endendself.last_priority = txr.last_priority--self.sep_key = txr.sep_keyreturn selfend-- appende una lista di stringhe o frammenti di citazionefunction Fragment:appends(fragments)for _,f in ipairs(fragments) doself:append(f)endreturn selfend-- collassa il frammento in una stringa e la restituisceFragment_mt.__tostring = function(tx)return table.concat(tx, '')end-- =====================================================================-- Fine definizione oggetto Fragment-- =====================================================================--[[ ===============================================================================Formatta un wikilink interno o un link esterno a un documento- options.code_id: codice per il link esterno- options.id: etichetta del link esterno o id del documento- options.encode: se true o nil l'url viene codificato (en:Percent-encoding)- options.link: link alla voce wiki sul codice documento- options.label: etichetta del link alla voce wiki sul codice documento- options.separator: separatore tra codice e link (di default uno spazio unificatore)- options.pattern: pattern del link in cui "$1" è l'id normale e "$2" l'id nell'url esterno===============================================================================]]local function link_id(options)local url_string = options.code_id or options.id;if options.encode == true or options.encode == nil thenurl_string = mw.uri.encode( url_string );endfor w in mw.ustring.gmatch( options.pattern, '$1' ) dooptions.pattern = mw.ustring.gsub( options.pattern, '^(%[[^%[]%S+)$1(.-%])', '%1$2%2' );options.pattern = mw.ustring.gsub( options.pattern, '([^%[]%[[^%[]%S+)$1(.-%])', '%1$2%2' );endreturn mw.ustring.format( '[[%s|%s]]%s%s',options.link, options.label, options.separator or "&nbsp;",substitute( options.pattern, {mw.text.nowiki(options.id), url_string} ));end--[[ ===============================================================================Determina se un URL è corretto. Al momento controlla solo la stringa inizia conprefisso URI valido e che non contenga spaziTODO: aggiungere controlli più stringenti (vedi en.wiki)===============================================================================]]local function check_url( url_str )-- se contiene spazi non può essere un url correttoif nil == url_str:match ("^%S+$") thenreturn false;end-- Protocol-relative or URL schemereturn url_str:sub(1,2) == "//" or url_str:match( "^[^/]*:" ) ~= nil;end--[[ ===============================================================================Rende una stringa sicura per essere usata come descrizione di un url===============================================================================]]local function safe_for_url( str )if str:match( "%[%[.-%]%]" ) ~= nil thentable.insert( z.message_tail, { set_error( 'wikilink_in_url', {}, true ) } );endreturn str:gsub( '[%[%]\n]', {['['] = '&#91;',[']'] = '&#93;',['\n'] = ' ' } );end--[[ ===============================================================================Formatta un collegamento esterno con controllo degli errori- URL: url del link esterno- label: etichetta del link esterno (se non inserita viene usato URL come etichetta e segnalato l'errore)- source: parametro in cui è contenuto l'url===============================================================================]]local function external_link( URL, label, source )local error_str = "";if not is_set( label ) thenlabel = URL;if is_set( source ) thenerror_str = set_error( 'bare_url_missing_title', { wrap( 'parameter', source ) }, false, " " );elseerror( cfg.messages["bare_url_no_origin"] );endendif not check_url( URL ) thenerror_str = set_error( 'bad_url', {}, false, " " ) .. error_str;endreturn table.concat({ "[", URL, " ", safe_for_url( label ), "]", error_str });end--[[ ===============================================================================Aggiunta collegamenti multipli, per ora usati solo dal modulo Collegamenti esterni===============================================================================]]local function append_links(value, links)if type(links) == 'table' thenfor _, t in ipairs(links) dot[2] = is_italicizable( t[2] ) and wrap( 'italic-title', t[2] ) or t[2]value = value .. ' / ' .. external_link( t[1], t[2] )endendreturn valueend--[[ ===============================================================================Formatta un DOI e controlla per errori===============================================================================]]local function doi(id, inactive)local cat = ""local handler = cfg.id_handlers['DOI'];local text;if is_set(inactive) thenlocal inactive_year = inactive:match("%d%d%d%d") or ''--text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;if is_set(inactive_year) thentable.insert( z.error_categories, "Pagine con DOI inattivo dal " .. inactive_year );elsetable.insert( z.error_categories, "Pagine con DOI inattivo" );-- when inactive doesn't contain a recognizable yearendinactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"endtext = link_id({link = handler.link, label = handler.label,pattern=handler.pattern,id=id,separator=handler.separator, encode=handler.encode}) .. (inactive or '')if nil == id:match("^10%.[^%s–]-/[^%s–]-[^%.,]$") then-- doi must begin with '10.', must contain a fwd slash, must not contain spaces or endashes, and must not end with period or commacat = set_error( 'bad_doi' );endreturn text .. catend--[[ ===============================================================================Formatta un link a Open library e controlla per errori===============================================================================]]local function open_library(id)local code = id:sub(-1,-1)local handler = cfg.id_handlers['OL'];if ( code == "A" ) thenreturn link_id({link=handler.link, label=handler.label,pattern="[[openlibrary:authors/OL$1|$1]]",id=id, separator=handler.separator,encode = handler.encode})elseif ( code == "M" ) thenreturn link_id({link=handler.link, label=handler.label,pattern="[[openlibrary:books/OL$1|$1]]",id=id, separator=handler.separator,encode = handler.encode})elseif ( code == "W" ) thenreturn link_id({link=handler.link, label=handler.label,pattern= "[[openlibrary:works/OL$1|$1]]",id=id, separator=handler.separator,encode = handler.encode})elsereturn link_id({link=handler.link, label=handler.label,pattern= "[[openlibrary:OL$1|$1]]",id=id, separator=handler.separator,encode = handler.encode}) ..' ' .. set_error( 'bad_ol' );endend--[[ ===============================================================================Formatta un link alla libreria Opac mediante SBN e controlla per errori===============================================================================]]local function sbn(id)local handler = cfg.id_handlers['SBN']local start_match, end_match, cd1, cd2 = string.find(id, '^IT\\ICCU\\(...)\\(%d+)')if not(cd1 and cd2) thenstart_match, end_match, cd1, cd2 = string.find(id, '^IT\\ICCU\\(....)\\(%d+)')endif cd1 and cd2 thenreturn link_id({link=handler.link, label=handler.label,pattern='[http://opac.sbn.it/bid/$1 $1]', id = id, code_id=cd1 .. cd2,encode =handler.encode})elsereturn link_id({link=handler.link, label=handler.label,pattern='[http://opac.sbn.it/bid/$1 $1]', id = id,encode =handler.encode}) .. ' ' .. set_error('bad_sbn')endend--[[ ===============================================================================Nice Opaque Identifiern utilisé par les formats Ark pour générer une cléadattato da fr:Module:Biblio/Références===============================================================================]]local function ark_id( base )base = tostring( base )if base thenlocal xdigits = '0123456789bcdfghjkmnpqrstvwxz'local sum = 0 local positionfor i = 1, base:len() doposition = xdigits:find( base:sub( i, i ), 1, true ) or 1sum = sum + i * ( position - 1 )endlocal index = sum % 29 + 1return xdigits:sub( index, index )endend--[[ ===============================================================================Formatta un link alla Bibliothèque Nationale de France e controlla per erroriadattato da fr:Module:Biblio/Références===============================================================================]]local function bnf(id)local handler = cfg.id_handlers['BNF']if id thenlocal txt = idlocal error_code = ''local bnf_id = id:upper():match( 'BNF(%d+%w)' ) or id:lower():match( 'cb(%d+%w)' ) or id:match( '^%d+%w' )if bnf_id then-- bnf contient une suite de chiffres qui peut être un ark validelocal base = bnf_id:sub( 1, 8 )if bnf_id:len() == 8 then -- il manque la clé, on l'ajouteid = base .. ark_id( 'cb' .. base )txt = baseelseif bnf_id:len() > 8 and bnf_id:sub( 9, 9 ) == ark_id( 'cb' .. base ) then-- ark valideid = bnf_id:sub( 1, 9 )txt = baseelse-- ark qui semble non valideid = bnf_idtxt = bnf_iderror_code = set_error('bad_bnf')endelse-- le paramètre ne semble pas un ark valideerror_code = set_error('bad_bnf')end-- dans tous les cas on renvoie l'adresse, on catégorise juste pour vérifier ce qui ne va pasreturn link_id( {link=handler.link,label=handler.label,pattern=handler.pattern,id=txt,code_id=bnf_id,separator=handler.separator} ) .. ' ' .. error_codeendend--[[ ===============================================================================Rimuove text e trattini irrilevanti da un numero isbn===============================================================================]]local function clean_isbn( isbn_str )return isbn_str:gsub( "[^-0-9X]", "" );end--[[ ===============================================================================Determina se una stringa ISBN è valida===============================================================================]]local function check_isbn( isbn_str )isbn_str = clean_isbn( isbn_str ):gsub( "-", "" );local len = isbn_str:len();if len ~= 10 and len ~= 13 thenreturn false;endlocal temp = 0;if len == 10 thenif isbn_str:match( "^%d*X?$" ) == nil then return false; endisbn_str = { isbn_str:byte(1, len) };for i, v in ipairs( isbn_str ) doif v == string.byte( "X" ) thentemp = temp + 10*( 11 - i );elsetemp = temp + tonumber( string.char(v) )*(11-i);endendreturn temp % 11 == 0;elseif isbn_str:match( "^%d*$" ) == nil then return false; endisbn_str = { isbn_str:byte(1, len) };for i, v in ipairs( isbn_str ) dotemp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );endreturn temp % 10 == 0;endend--[[ ===============================================================================Ritorna la sola etichetta visibile di un wikilink===============================================================================]]local function remove_wikilink( str )-- Sia [[A|B]] che [[B]] ritornano Breturn (str:gsub( "%[%[([^%[%]]*)%]%]", function(l)return l:gsub( "^[^|]*|(.*)$", "%1" ):gsub("^%s*(.-)%s*$", "%1");end));end--[[ ===============================================================================Riconosce le date nel formato ISO yyyy-mm-dd e le riformatta in dmy. Si assicurache 01 e 1 siano resi come 1º qualora indichino il giorno.===============================================================================]]local function get_date(str)if is_set(str) thenlocal try_year, try_month, try_day = string.match(str, '^(%d%d%d%d)-(%d%d)-(%d%d)$')if try_day thenlocal Month = cfg.months[tonumber(try_month)]if Month thentry_day = try_day == '01' and '1º' or tonumber(try_day)return string.format("%s %s %s", try_day, Month, try_year)endendtry_day, try_month, try_year = string.match(str, '^(%d%d?) (%a+) (%d%d%d%d)$')if try_day thentry_day = (try_day == '1' or try_day == '01') and '1º' or tonumber(try_day)return string.format("%s %s %s", try_day, try_month, try_year)endendreturn strend--[[ ===============================================================================Unisce year, day e month ritornando la data come un'unica stringa.month è controllato solo se year è definito, e day è controllato solo se month è definito.Se month è un numero tenta di convertilo nel nome corrispondente (1->gennaio, 2->febbraio...),altrimenti non lo modifica===============================================================================]]local function get_date_yyyy_mm_dd(year, month, day)local date = yearif is_set(date) thenif is_set(month) thenlocal month = cfg.months[tonumber(month)] or monthdate = month .. " " .. yearif is_set(day) thenif day == "01" or day=="1" then day="1º" enddate = day .. " " .. dateendendreturn dateendreturn ""end--[[ ===============================================================================Suppone che str sia una data ben formata (una delle varianti "gg mm aaaa","gg/mm/aaaa" o "gg-mm-aaaa") e restituisce l'articolo da anteporre per citarlacome data di accesso/archivio===============================================================================]]local function article_date(str)local start = mw.ustring.sub(str, 1, 2)if in_array( start, {'08', '8 ', '8-', '8/', '11'} ) thenreturn " l'"elseif mw.ustring.find(str, '^pre ') then -- per i valori "pre x/x/x" inseriti da ArchiveBotreturn ' in data 'endreturn str ~= '' and " il " or ''end--[[ ===============================================================================Controlla che la stringa passata sia in un formato ammesso in caso contrario ritorna il codice di errore===============================================================================]]local function check_time(str)local h,m,s = string.match(str, '^(%d+):(%d+):(%d+)$')if not(h) then h,m,s = string.match(str, '^(%d+) h (%d+) min (%d+) s$') endif not(m) then m,s = string.match(str, '^(%d+) min (%d+) s$') endif not(m) then m,s = string.match(str, '^(%d+):(%d+)$') endif not(m) then m = string.match(str, '^(%d+) min$') endif not(m) then return 'time_not_valid' endif tonumber(m) >= 60 then return 'minutes_wrong' endif s and tonumber(s) >= 60 then return 'seconds_wrong' endif h and not(tonumber(s)) then return 'hour_wrong' endreturn nilend--[[ ===============================================================================Formatta una lista di persone (autori o editori)===============================================================================]]local function list_people(control, people)local sep = control.sep;local lastsep = control.lastseplocal text = {}local etal = control.etallocal coauthors = control.coauthorslocal person_list = {}for i,person in ipairs(people) dolocal last = person.lastif is_set(last) thenlocal fullname = ""local first = person.firstif is_set(first) thenif invertorder then first, last = last, first endfullname = table.concat({first, person.last}, ' ')elsefullname = person.lastendif is_set(person.link) then fullname = table.concat({"[[", person.link, "|", fullname, "]]"}) endtable.insert( person_list, fullname )endif etal thenbreakendendlocal count = #person_listlocal result = "" if count > 0 thenif coauthors thenresult = table.concat(person_list, sep)elseif etal thenresult = person_list[1] .. cfg.messages['et al']elseresult = mw.text.listToText(person_list, sep, lastsep)endendreturn result, countend--[[ ===============================================================================Genera un id per un ancora CITEREF===============================================================================]]local function anchor_id( options )return "CITEREF" .. table.concat( options );end--[[ ===============================================================================Estrae una lista di nomi (autori o editori) dalla lista argomenti===============================================================================]]local function extract_names(args, list_name, parent_name)local names = {};local i = 1;local last;local parameters = {first = cfg.aliases[list_name .. '-First'],last = cfg.aliases[list_name .. '-Last'],link = cfg.aliases[list_name .. '-Link'],}if parent_name thenfor k, t in pairs(parameters) dolocal new_values = {}for _, v in ipairs(t) dotable.insert( new_values, substitute(v, parent_name) )endparameters[k] = new_valuesendendwhile true dolast = select_one( args, parameters.last, 'redundant_parameters', i );if not is_set(last) thenlocal first = select_one( args, parameters.first, 'redundant_parameters', i )if not is_set(first) thenbreak;else -- nel caso sia definito "nome" ma non "cognome"names[i] = {last = first,first = '',link = select_one( args, parameters.link, 'redundant_parameters', i ),}endelsenames[i] = {last = last,first = select_one( args, parameters.first, 'redundant_parameters', i ),link = select_one( args, parameters.link, 'redundant_parameters', i ),};endi = i + 1;endreturn names;end--[[ ===============================================================================Estrae dagli argomenti i codici bibliografici riconosciuti usando latabella cfg.id_handlers===============================================================================]]local function extract_ids( args )local id_list = {};for k, v in pairs( cfg.id_handlers ) dov = select_one( args, v.parameters, 'redundant_parameters' );if is_set(v) thenif k == 'ISBN' then v = string.gsub(v, '^ISBN%s*', '') end -- hack per eliminare l'ISBN ripetutoid_list[k] = v;endendreturn id_list;end--[[ ===============================================================================Formatta gli id bibliografici presenti nella tabella id_list===============================================================================]]local function build_id_list( id_list, options )local new_list, handler = {};local function fallback(k)return { __index = function(t,i) return cfg.id_handlers[k][i] end }end;local function comp( a, b )return a[1] < b[1];endfor k, v in pairs( id_list ) do-- fallback to read-only cfglocal handler = setmetatable( { ['id'] = v }, fallback(k) );if k == 'DOI' thentable.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );elseif k == 'OL' thentable.insert( new_list, {handler.label, open_library( v ) } );elseif k == 'SBN' thentable.insert (new_list, {handler.label, sbn(v) } );elseif k == 'BNF' thentable.insert (new_list, {handler.label, bnf(v) } );elseif k == 'ISBN' thenlocal ISBNif v == 'non esistente' or v == 'no' then --la forma lunga per intercettare il valore ritornato dal template NoIsbnISBN = 'ISBN non esistente'elseISBN = link_id( handler );if not check_isbn( v ) and not is_set(options.IgnoreISBN) thenISBN = ISBN .. set_error( 'bad_isbn', {}, false, "<sup>", "</sup>" );endendtable.insert( new_list, {handler.label, ISBN } );elsetable.insert( new_list, {handler.label, link_id( handler ) } );endendtable.sort( new_list, comp );for k, v in ipairs( new_list ) donew_list[k] = v[2];endreturn new_list;end--[[ ===============================================================================Genera la stringa per il formato, se format non è definita tenta di ricavarlo dall'url===============================================================================]]local function get_format(format, url)if format:lower() == 'html' thenreturn ''elseif not is_set(format) thenformat = mw.ustring.match(url, "^.*%.(.+)$" ) or ''if not cfg.external_link_type[format:lower()] thenformat = mw.ustring.match(format, "^(.+)#.+$") or ''if not cfg.external_link_type[format:lower()] thenreturn ''endendend-- Se il formato esterno è tra quelli previsti imita lo stile dei template {{PDF}} o {{doc}}local f = cfg.external_link_type[format:lower()]if f thenreturn mw.ustring.format(' (<span style="font-weight: bolder; font-size:80%%"><abbr title="%s">%s</abbr></span>)', f.text, f.label)elsetable.insert( z.message_tail, { set_error('unknown_format', format, true) } );return mw.ustring.format(' (%s)', format)endend--[[ ===============================================================================Genera la citazione===============================================================================]]local function citation0( config, args )local A = argument_wrapper( args );local ilocal Stylename = A['Style']local Style = cfg.stylelocal PPPrefix = (is_set( A['NoPP'] ) and "") or Style.ppprefixlocal PPrefix = (is_set( A['NoPP'] ) and "") or Style.pprefix-- Pick out the relevant fields from the arguments. Different citation templates-- define different field names for the same underlying things.-- local Authors = A['Authors'];local a = extract_names( args, 'AuthorList' );local Coauthors = A['Coauthors'];local Others = A['Others'];local Editors = A['Editors'];local e = extract_names( args, 'EditorList' );------------------------------------------------- Get date datalocal PublicationDate = A['PublicationDate'];local LayDate = A['LayDate'];------------------------------------------------- Get title datalocal Title = A['Title'];local Conference = A['Conference'];local Organization = A['Organization']local TransTitle = A['TransTitle'];local OriginalTitle = A['OriginalTitle']-- local TitleNote = A['TitleNote'];local TitleLink = A['TitleLink'];local Chapter = A['Chapter'];local ChapterLink = A['ChapterLink'];local TransChapter = A['TransChapter'];local TitleType = A['TitleType'];local ArchiveURL = A['ArchiveURL'];local URL = A['URL']local URLorigin = A:ORIGIN('URL');local ChapterURL = A['ChapterURL'];local ChapterURLorigin = A:ORIGIN('ChapterURL');local ConferenceURL = A['ConferenceURL'];local ConferenceURLorigin = A:ORIGIN('ConferenceURL');local Abstract = A['Abstract']local Periodical = A['Periodical'];local Illustrator = A['Illustrator'];local Translator = A['Translator'];local Institution = A['Institution'];local Collection = A['Collection'];local SupplementOf = A['SupplementOf'];if is_set(OriginalTitle) and not is_set(TransTitle) thenTransTitle = OriginalTitleendlocal isPubblicazione = (config.CitationClass == 'pubblicazione') or(config.CitationClass=='testo' and is_set(Periodical))-------------------------------------------------------------------------------- Formattazione di Position - contiene la pagina/posizione o punto del video-- a cui fa riferimento la fonte------------------------------------------------------------------------------local Position = A['Position'];local PositionOrigin=A:ORIGIN('Position')if is_set(Position) thenif PositionOrigin == "p" thenPosition = PPrefix .. Positionelseif PositionOrigin == "pp" thenPosition = PPPrefix .. Positionelseif PositionOrigin ~= "posizione" thentable.insert( z.error_categories, 'Voci con modulo citazione e parametro ' .. PositionOrigin )if PositionOrigin == "pagine" thenif config.CitationClass == "libro" thenif tonumber(Position) thenPosition = PPrefix .. Positionelseif string.find(Position, '^%d') thenPosition = PPPrefix .. Positionendelseif config.CitationClass=="conferenza" or config.CitationClass== "pubblicazione" thenPosition = (tonumber(Position) and PPrefix or PPPrefix) .. Positionendelseif PositionOrigin == "pagina" thenPosition = PPrefix .. PositionelsePosition = PPPrefix .. Positionendendendlocal Hour = A['Hour']local Minutes = A['Minutes']local Seconds = A['Seconds']local Time = A['Time']if in_array(config.CitationClass, { "video", "tv", "audio" } ) thenlocal ComposeTime = {}local TimeError = {}if is_set(Hour) thenif not is_set(Minutes) then TimeError[#TimeError+1] = set_error('need_minutes' , {'ora'}) endif not tonumber(Hour) then TimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'ora'}) endComposeTime[#ComposeTime+1] = Hour .. '&nbsp;h'endif is_set(Minutes) thenlocal check_error = tonumber(Minutes)if not check_error thenTimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'minuto'})elseif check_error > 60 thenTimeError[#TimeError+1] = set_error('minutes_wrong')end ComposeTime[#ComposeTime+1] = Minutes .. '&nbsp;min'endif is_set(Seconds) thenif not is_set(Minutes) then TimeError[#TimeError+1] = set_error('need_minutes', {'secondo'}) endlocal check_error = tonumber(Seconds)if not check_error thenTimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'ora'})elseif check_error > 60 thenTimeError[#TimeError+1] = set_error('seconds_wrong')endComposeTime[#ComposeTime+1] = Seconds .. '&nbsp;s'endif #ComposeTime > 1 thenif is_set(Position) then TimeError[#TimeError+1] = set_error('time_parameter_conflict') endPosition = 'a ' .. table.concat(ComposeTime, '&nbsp;')endif is_set(Time) thenif is_set(Position) then TimeError[#TimeError+1] = set_error('time_parameter_conflict') endlocal check_error = check_time(Time)if check_error then TimeError[#TimeError+1] = set_error(check_error) endPosition = 'a ' .. Timeendif #TimeError > 0 then Position = Position .. " " .. table.concat(TimeError, ", ") endelseif is_set(Hour) or is_set(Minutes) or is_set(Seconds) or is_set(Time) thentable.insert( z.message_tail, { set_error( 'not_video_citation', {}, true ) } );endendif is_set(Position) then Position = ' ' .. Position end-------------------------------------------------------------------------------- Formattazione di volume/numero/serie/episodio------------------------------------------------------------------------------local Series = A['Series'];local Volume = A['Volume'];local Issue = A['Issue'];if config.CitationClass == "tv" thenif is_set(Issue) thenif is_set(Volume) thenIssue = substitute(cfg.messages['season_episode'], {Volume, Issue} )Volume = ''elseIssue = substitute(cfg.messages['episode'], {Issue})endendelse-- formatta Volume e Issue considerando numeri anche le stringhe del tipo n-n o n/nif is_set(Volume) thenif tonumber(Volume:gsub('[-/]', ''), 10) or A:ORIGIN('Volume') == "vol" thenVolume = "vol.&nbsp;" .. Volumeendendif is_set(Issue) thenif tonumber(Issue:gsub('[-/]', ''), 10) thenIssue = "n.&nbsp;" .. Issueendendendlocal Edition = A['Edition'];local Place = A['Place']local PublisherName = A['PublisherName'];local SubscriptionRequired = A['SubscriptionRequired'];local Via = A['Via'];-- local Agency = A['Agency'];local DeadURL = A['DeadURL'];local Language = A['Language'];local Format = A['Format'];local Ref = A['Ref'];local DoiBroken = A['DoiBroken'];local ID = A['ID'];local IgnoreISBN = A['IgnoreISBN'];local Quote = A['Quote'];local sepc = Style.seplocal sepcspace = sepc .. " "local PostScript = first_set(A['PostScript'], Style['postscript']);local no_tracking_cats = A['NoTracking'];local use_lowercase = ( sepc ~= '.' );local this_page = mw.title.getCurrentTitle(); --Also used for COinSlocal ID_list = extract_ids( args );if ( isPubblicazione ) thenif not is_set(URL) and not is_set(TitleLink) thenif is_set(ID_list['PMC']) thenlocal Embargo = A['Embargo'];if is_set(Embargo) thenlocal lang = mw.getContentLanguage();local good1, result1, good2, result2;good1, result1 = pcall( lang.formatDate, lang, 'U', Embargo );good2, result2 = pcall( lang.formatDate, lang, 'U' );if good1 and good2 and tonumber( result1 ) < tonumber( result2 ) thenURL = "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];URLorigin = cfg.id_handlers['PMC'].parameters[1];endelseURL = "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];URLorigin = cfg.id_handlers['PMC'].parameters[1];endelseif is_set(ID_list['DOI']) thenURL = "https://oadoi.org/" .. ID_list['DOI'];URLorigin = cfg.id_handlers['DOI'].parameters[1];endendendID_list = build_id_list( ID_list, {DoiBroken = DoiBroken, IgnoreISBN = IgnoreISBN} );local Station = A['Station'];if is_set(Station) thenlocal wkStation = A['StationLink']if is_set(wkStation) thenStation = '[[' .. wkStation .. '|' .. Station .. ']]'endendif config.CitationClass == "tv" thenChapter = Title;ChapterLink = TitleLink;TransChapter = TransTitle;Title = Series;TitleLink = A['SeriesLink'];TransTitle = '';Series = '';end-------------------------------------------------------------------------------- Se url è in realtà un url archiviato, lo tratta come tale-- (per ora riconosce solo Internet Archive)------------------------------------------------------------------------------local formatoIA = '^https?://web%.archive%.org/w?e?b?/?%d+/'if is_set(URL) and is_set(Title) and URL:match(formatoIA) and not is_set(ArchiveURL) thenArchiveURL = URLURL = URL:gsub(formatoIA,'')if not URL:match('://') thenURL = 'http://' .. URLendend-------------------------------------------------------------------------------- Se opera/sito non è specificata, nel caso dei siti usa il dominio dell'URL------------------------------------------------------------------------------local auto_Periodical = falseif in_array(config.CitationClass, {'web'}) and not is_set(Periodical) and is_set(URL) thenPeriodical = mw.ustring.match(URL, "//([^/#%?]*)") or ''-- tolgo anche eventuale www.if string.find(Periodical, "^[Ww][Ww][Ww]%.") thenPeriodical = mw.ustring.sub(Periodical, 5)end-- evito ripetizione se il dominio è stato usato come titolo o editoreif is_set(Periodical) thenif mw.ustring.lower(Title) == mw.ustring.lower(Periodical) thenPeriodical = ''endif mw.ustring.lower(PublisherName) == mw.ustring.lower(Periodical) thenPublisherName = ''endendauto_Periodical = trueend-------------------------------------------------------------------------------- Se compare uno dei parametri legati a una pubblicazione periodica (opera, rivista, ec...)-- e non è definito capitolo, ma solo titolo sposto titolo a capitolo------------------------------------------------------------------------------if is_set(Periodical) and not is_set(Chapter) and is_set(Title) thenChapter = Title;ChapterLink = TitleLink;TransChapter = TransTitle;Title = '';TitleLink = '';TransTitle = '';end----------------------------------------------------------------- Compone la stringa della lingua---------------------------------------------------------------local Language_code = ""local first_language = ""if is_set(Language) thenif Language:sub(1,1) == "(" thenLanguage_code = Languageelselocal frame_lingue = {return_error='true'}for lingua in mw.text.gsplit(Language, ',', true) dolingua = mw.text.trim(lingua)if lingua ~= '' thenframe_lingue[#frame_lingue+1] = linguaendendif #frame_lingue > 1 or (#frame_lingue==1 and frame_lingue[1]:lower()~="it" and frame_lingue[1]:lower()~="it-it") thenfirst_language = frame_lingue[1]:lower();local lg_error;Language_code, lg_error = require("Modulo:Lingue").lingue(frame_lingue)if lg_error and #lg_error > 0 thenlocal error_string = mw.text.listToText(lg_error, ", ", " e " )table.insert( z.message_tail, { set_error('unknown_language', {error_string}, true) } );endendendendif is_set(Edition) thenif A:ORIGIN('Edition') == "ed" or tonumber(Edition) thenEdition = Edition .. "ª&nbsp;ed."endend-------------------------------------------------------------------------------- Aggiunge il wikilink a Wikisource------------------------------------------------------------------------------if is_set(A['Source']) and not in_array(config.CitationClass, { "web", "video", "tv", "audio" } ) thenlocal source = A['Source']-- se s=1 usa lo stesso valore di titolo/capitoloif source == "1" thensource = Title .. (is_set(Chapter) and ("/" .. Chapter) or "")endsource = "s:" .. (is_set(first_language) and (first_language .. ":") or "") .. sourceif is_set(Chapter) then ChapterLink = sourceelse TitleLink = source endend-------------------------------------------------------------------------------- Recupero e formatto lista autori------------------------------------------------------------------------------local AuthorSeparator = Style.peopleseplocal control = {sep = AuthorSeparator,maximum = Style.maximum_authors,lastsep = Style.lastsepauthor,invertorder = Style.invertorder,etal = false,coauthors = false,};local Etal = A['Etal']-- If the coauthor field is also used, prevent adding ''et al.''if is_set(Coauthors) thentable.insert( z.error_categories, 'Voci con modulo citazione e parametro ' .. A:ORIGIN('Coauthors') )control.coauthors = trueelseif is_set(Etal) thencontrol.etal = trueendlocal Authors = list_people(control, a)if not is_set(Authors) and is_set(Coauthors) then -- se non sono stati compilati campi autore, ma solo coautoriAuthors = CoauthorsCoauthors = ""elseif is_set(Coauthors) thenAuthors = table.concat({Authors, AuthorSeparator, Coauthors})end-------------------------------------------------------------------------------- Recupero e formatto lista curatori------------------------------------------------------------------------------local msg_editorslocal CuratoriEtal = A['Etalcuratori']control.coauthors = falsecontrol.etal = is_set(CuratoriEtal)if is_set(Editors) thenmsg_editors = 'editors'elselocal EditorCountEditors, EditorCount = list_people(control, e)if is_set(Editors) thenmsg_editors = EditorCount <= 1 and 'editor' or 'editors'endend-------------------------------------------------------------------------------- Recupero e formatto lista autori e curatori di un singolo capitolo dell'opera citata------------------------------------------------------------------------------local msg_chapter_editorslocal Contributors, ChapterEditors = "", ""if is_set(Chapter) thenlocal ChapterEditorCountcontrol.etal = falseContributors = list_people(control,extract_names( args, 'ContributorList', A:ORIGIN('Chapter') ))ChapterEditors, ChapterEditorCount = list_people(control,extract_names( args, 'ChapterEditorList', A:ORIGIN('Chapter') ))if is_set(ChapterEditors) thenmsg_chapter_editors = ChapterEditorCount <= 1 and 'editor' or 'editors'endend-------------------------------------------------------------------------------- Se conferenza aggiungo il campo Organizzazione------------------------------------------------------------------------------if config.CitationClass == 'conferenza' thenif is_set (Authors) and is_set(Organization) thenAuthors = table.concat({Authors, ', ', Organization})elseif is_set(Organization) thenAuthors = OrganizationendOrganization = ""end-------------------------------------------------------------------------------- Formatto la data------------------------------------------------------------------------------local Date = get_date(A['Date'])local Year = A['Year']if not is_set(Date) then Date=get_date_yyyy_mm_dd(Year, A['Month'], A['Day']) endlocal OrigDate = get_date(A['OrigDate'])if not is_set(OrigDate) then OrigDate=get_date_yyyy_mm_dd(A['OrigYear'], A['OrigMonth'], A['OrigDay']) endlocal AccessDate = get_date(A['AccessDate'])if not is_set(AccessDate) then AccessDate=get_date_yyyy_mm_dd(A['AccessYear'], A['AccessMonth'], A['AccessDay']) endlocal ArchiveDate = get_date(A['ArchiveDate']);if is_set(OrigDate) and not is_set(Date) thenDate = OrigDateOrigDate = ""endOrigDate = is_set(OrigDate) and (" " .. wrap( 'origdate', OrigDate)) or "";if in_array(PublicationDate, {Date, Year}) then PublicationDate = '' endif not is_set(Date) and is_set(PublicationDate) thenDate = PublicationDate;PublicationDate = '';end-- Captures the value for Date prior to adding parens or other textual transformationslocal DateIn = Date;if not is_set(URL) andnot is_set(ChapterURL) andnot is_set(ArchiveURL) andnot is_set(ConferenceURL) then-- Controlla se Cita web viene chiamato senza URLif in_array(config.CitationClass, {'web'}) thentable.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } );end-- Test if accessdate is given without giving a URLif is_set(AccessDate) thentable.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } );AccessDate = '';end-- Test if format is given without giving a URLif is_set(Format) thenFormat = Format .. set_error( 'format_missing_url' );endend-- Test if citation has no titleif not is_set(Chapter) andnot is_set(Title) andnot is_set(Periodical) andnot is_set(Conference) andnot is_set(TransTitle) andnot is_set(TransChapter) thentable.insert( z.message_tail, { set_error( 'citation_missing_title', {}, true ) } );end-- genera la stringa per il formatoFormat = get_format(Format, (is_set(URL) and URL) or ChapterURL )-- In maniera predefinita l'URL non è dichiarato mortoif is_set(DeadURL) thenDeadURL = DeadURL:lower() ~= 'no'else-- A meno che l'archivio non sia specificatoDeadURL = is_set(ArchiveURL)endlocal OriginalURL = URLif is_set( ArchiveURL ) thenif DeadURL thenURL = ArchiveURLURLorigin = A:ORIGIN('ArchiveURL')endend----------------------------------------------------------------- se pubblicazione controlla per i parametro abstract--------------------------------------------------------------if is_set(Abstract) thenif isPubblicazione thenif is_set(ChapterURL) thenTitleType = external_link( ChapterURL, 'abstract' )ChapterURL = ""if not is_set(URL) then Format = "" endelseif is_set(URL) thenTitleType = external_link( URL, 'abstract' )URL = ""elseAbstract = ''endelseAbstract = ""endelseAbstract = ""endTitleType = is_set(TitleType) and ("(" .. TitleType .. ")") or "";----------------------------------------------------------------- Format chapter / article title---------------------------------------------------------------local TransError = ""if is_set(TransChapter) thenif not is_set(Chapter) thenTransError = " " .. set_error( 'trans_missing_chapter' )Chapter = TransChapterTransChapter = ""elseTransChapter = wrap( 'trans-italic-title', TransChapter )endendChapter = is_italicizable( Chapter ) and wrap( 'italic-title', Chapter ) or Chapter;if is_set(TransChapter) then Chapter = Chapter .. " " .. TransChapter endif is_set(Chapter) thenif is_set(ChapterLink) thenChapter = table.concat({"[[", ChapterLink, "|", Chapter, "]]"})elseif is_set(ChapterURL) thenChapter = external_link( ChapterURL, Chapter ) .. TransError;if not is_set(URL) then --se è settato URL conservo Format per inserirlo dopo questoChapter = Chapter .. Format;Format = "";endelseif is_set(URL) thenChapter = external_link( URL, Chapter ) .. TransError;Chapter = append_links(Chapter, args.altrilink)Chapter = Chapter .. Format;URL = "";Format = "";elseChapter = Chapter .. TransError;endelseif is_set(ChapterURL) thenChapter = external_link( ChapterURL, nil, ChapterURLorigin ) .. TransErrorend----------------------------------------------------------------- Format main title---------------------------------------------------------------TransError = "";if is_set(TransTitle) thenif not is_set(Title) thenTransError = " " .. set_error( 'trans_missing_title' )Title = TransTitleTransTitle = ""elseTransTitle = wrap( 'trans-italic-title', TransTitle )endendTitle = is_italicizable( Title ) and wrap('italic-title', Title ) or Title;if is_set(TransTitle) then Title = Title .. " " .. TransTitle endif is_set(Title) thenif is_set(TitleLink) thenTitle = "[[" .. TitleLink .. "|" .. Title .. "]]"elseif is_set(URL) thenTitle = external_link( URL, Title ) .. TransErrorTitle = append_links(Title, args.altrilink)Title = Title .. FormatURL = "";Format = "";elseTitle = Title .. TransError;endend----------------------------------------------------------------- Format Conference---------------------------------------------------------------if is_set(Conference) thenConference = wrap('italic-title', Conference )if is_set(ConferenceURL) thenConference = external_link( ConferenceURL, Conference );endelseif is_set(ConferenceURL) thenConference = external_link( ConferenceURL, nil, ConferenceURLorigin );end-- se URL non è stato consumato da un capitolo/titolo emette erroreif is_set(URL) thenURL = " " .. external_link( URL, nil, URLorigin );end--Aggiungo le virgolette alla citazione-if is_set(Quote) thenQuote = wrap( 'quoted-text', Quote );end----------------------------------------------------------------- Parametro via e subscription---------------------------------------------------------------if is_set(Via) thenif is_set(SubscriptionRequired) thenVia = wrap( 'viasubscription', Via );elseVia = wrap('via', Via);endelseif is_set(SubscriptionRequired) thenVia = wrap('subscription')end----------------------------------------------------------------- Formattazione dati di accesso/url di archivio---------------------------------------------------------------if is_set(AccessDate) thenAccessDate = substitute( cfg.messages['retrieved'], {AccessDate, article_date(AccessDate)} )endlocal Archivedif is_set(ArchiveURL) thenlocal decodeArchiveDate = require('Modulo:Webarchive').decodeArchiveDatelocal ArchiveURLDate = decodeArchiveDate(ArchiveURL)local ArchiveError, ArchiveOutput = ''if not is_set(ArchiveDate) thenArchiveDate = ArchiveURLDate or ''if not ArchiveURLDate thenArchiveError = set_error('archive_missing_date', {}, false, ' ')endelseif ArchiveURLDate and ArchiveURLDate ~= ArchiveDate thenArchiveError = set_error('date_mismatch', {ArchiveURLDate}, false, ' ')endArchiveOutput = ArchiveDate .. ArchiveErrorlocal ArchiveURL2 = A['ArchiveURL2']local ArchiveDate2 = get_date(A['ArchiveDate2'])if is_set(ArchiveURL2) thenlocal ArchiveURLDate2 = decodeArchiveDate(ArchiveURL2)local ArchiveError2, ArchiveOutput2 = ''if not is_set(ArchiveDate2) thenArchiveDate2 = ArchiveURLDate2 or ''if not ArchiveURLDate2 thenArchiveError2 = set_error('archive_missing_date2', {}, false, ' ')endelseif ArchiveURLDate2 and ArchiveURLDate2 ~= ArchiveDate2 thenArchiveError2 = set_error('date2_mismatch', {ArchiveURLDate2}, false, ' ')endArchiveOutput2 = ArchiveDate2 .. ArchiveError2ArchiveURL2 = substitute(cfg.messages['archived-second-copy'],{ external_link( ArchiveURL2, cfg.messages['archived2']), ArchiveOutput2, article_date(ArchiveDate2) } );endif not DeadURL thenArchived = substitute( cfg.messages['archived-not-dead'],{ external_link( ArchiveURL, cfg.messages['archived'] ), ArchiveOutput, article_date(ArchiveDate),  ArchiveURL2} );if not is_set(OriginalURL) thenArchived = Archived .. set_error('archive_missing_url', {}, false, ' ');endelseif is_set(OriginalURL) thenArchived = substitute( cfg.messages['archived-dead'],{ OriginalURL, ArchiveOutput, article_date(ArchiveDate), ArchiveURL2 } );elseArchived = substitute( cfg.messages['archived-missing'],{ set_error('archive_missing_url'), ArchiveOutput, article_date(ArchiveDate), ArchiveURL2 } );endelseArchived = ""end----------------------------------------------------------------- Data originale se presente (in ordine di preferenza dopo-- la data di pubblicazione, quindi l'editore, il luogo di pubblicazione, )---------------------------------------------------------------if is_set(OrigDate) thenif is_set(Date) thenDate = Date .. " " .. OrigDateelseif is_set(PublisherName) thenPublisherName = PublisherName .. " " .. OrigDateelseif is_set(Place) thenPlace = Place .. " " .. OrigDateelseDate = OrigDateendend-- sopra si controlla se è vuoto, perciò bisogna formattarlo alla fine.if is_set(Periodical) then Periodical = wrap( 'italic-title', Periodical ) endif is_set(SupplementOf) then if not mw.ustring.find(SupplementOf, "^.+''.+''") thenSupplementOf = 'supplemento di ' .. wrap( 'italic-title', SupplementOf )endendif is_set(Collection) then Collection = 'collana ' .. wrap( 'italic-title', Collection ) endif is_set(Translator) then Translator = wrap('translator', Translator) endif is_set(Illustrator) then Illustrator = wrap('illustrator', Illustrator) end----------------------------------------------------------------- Combino insieme i vari componenti della citazione---------------------------------------------------------------local fragment_Titlelocal PostTitle = A['PostTitle']if is_set(Title) thenif DeadURL and not is_set( ArchiveURL ) then   -- Report a dead URL without an archived URLTitle = Title .. interrupted_url()endfragment_Title = Fragment.new({Title, Format, TitleType, PostTitle}, ' '):last(",")elsefragment_Title = Fragment.new({ })if is_set(Chapter) thenChapter = DeadURL and not is_set( ArchiveURL )and tostring(Fragment.new({Chapter, interrupted_url(), Format, TitleType, PostTitle}, ' '):last(""))or  tostring(Fragment.new({Chapter, Format, TitleType, PostTitle}, ' '):last(""))endendlocal fragment_citationif config.CitationClass == "tv" thenif is_set(Chapter) thenfragment_Title:last(":"):append(Fragment.new({Issue, Chapter}, sepc))Issue = ""endfragment_citation=Fragment.new({Authors}, sepc)fragment_citation:append(fragment_Title)elseif is_set(ChapterEditors) and (is_set(Contributors) or args["anteposizione-curatore"] == "no") thenChapterEditors = 'a cura di ' .. ChapterEditorsfragment_citation = Fragment.new({Contributors, Chapter, ChapterEditors}, sepc)elseif is_set(ChapterEditors) thenChapterEditors = wrap(msg_chapter_editors, ChapterEditors)endif is_set(Chapter) and not (is_set(Contributors) or is_set(ChapterEditors)) thenif is_set(Authors) thenContributors, Authors = Authors, ""elseif is_set(Editors) and args["anteposizione-curatore"] ~= "no" thenChapterEditors, Editors = wrap(msg_editors, Editors), ""endendfragment_citation = Fragment.new({is_set(Contributors) and Contributors or ChapterEditors, Chapter}, sepc)endif is_set(Chapter) then -- antepone "su" anzichè "in" per i siti webif A:ORIGIN('Periodical') == 'sito' or auto_Periodical thenfragment_citation:last("su")elsefragment_citation:last("in")endendif is_set(Editors) and (is_set(Authors) or args["anteposizione-curatore"] == "no" and not is_set(Chapter)) thenEditors = 'a cura di ' .. Editorsfragment_citation:appends({Authors, fragment_Title, Editors})elseif is_set(Editors) thenEditors = wrap(msg_editors, Editors)endfragment_citation:appends({is_set(Authors) and Authors or Editors, fragment_Title})endendfragment_citation:appends( { Conference, Periodical, SupplementOf, Collection, Translator, Illustrator, Others, Series,  Volume, Issue, Edition, Institution, Place, PublisherName, Station, Date, Position } )local fragment_ID_list = Fragment.new(ID_list, sepc):append(ID):start(",")local fragment_URL = Fragment.new(URL):start(",")local fragment_AccessDate = Fragment.new(AccessDate):start('.')local fragment_Archived = Fragment.new(Archived):start(' ')local fragment_Via = Fragment.new(Via):start(".")local fragment_Quote = Fragment.new({Quote}):start(".")fragment_citation:appends({fragment_ID_list, fragment_URL, fragment_AccessDate, fragment_Archived, fragment_Via})if PostScript == 'nessuno' thenfragment_citation:last("nothing")elsefragment_citation:last("..")endfragment_citation:appends({fragment_Quote})fragment_citation:start(" ")local text = Language_code .. tostring(fragment_citation)-- aggiungo l'icona per video/audioif config.CitationClass == "video" then text = cfg.messages['icon_video'] .. ' ' .. text endif config.CitationClass == "audio" then text = cfg.messages['icon_audio'] .. ' ' .. text end-- Now enclose the whole thing in a <span/> elementlocal options = {};if is_set(config.CitationClass) and config.CitationClass ~= "citation" thenoptions.class = "citation " .. config.CitationClass;elseoptions.class = "citation";end--  if string.len(text:gsub("<span[^>/]*>.-</span>", ""):gsub("%b<>","")) <= 2 then--      z.error_categories = {};--      text = set_error('empty_citation');--      z.message_tail = {};--  endif is_set(Ref) thentext = table.concat({ '<cite id="CITEREF', Ref, --mw.uri.anchorEncode('CITEREF' .. Ref),'" class="', mw.text.nowiki(options.class), '" style="font-style:normal">', text, "</cite>"})elsetext = table.concat({ '<cite class="', mw.text.nowiki(options.class), '" style="font-style:normal">', text, "</cite>"})endlocal empty_span = '<span style="display:none;">&nbsp;</span>';if #z.message_tail ~= 0 thentext = text .. " ";for i,v in ipairs( z.message_tail ) doif is_set(v[1]) thenif i== #z.message_tail thentext = text .. error_comment( v[1], v[2] );elsetext = text .. error_comment( v[1] .. "; ", v[2] );endendendend-- Chek to insert category errorif not is_set(no_tracking_cats) thenfor k, v in pairs( cfg.uncategorized_namespaces ) doif this_page.nsText == v thenno_tracking_cats = "true";break;endendendno_tracking_cats = no_tracking_cats:lower();if in_array(no_tracking_cats, {"", "no", "false", "n"}) thenfor _, v in ipairs( z.error_categories ) dotext = text .. '[[Categoria:' .. v ..']]';endendreturn textend--[[ ===============================================================================Funzione di interfaccia per la generazione della citazione, usata dai vari templatecita libro, cita news, ecc...===============================================================================]]function z.citation(frame)local pframe = frame:getParent()local args = {};local suggestions = {};local error_text, error_state;local config = {};for k, v in pairs( frame.args ) doconfig[k] = v;args[k] = v;endif config['ignore_parent'] == 's' thenpframe.args = {}endlocal ignore_unnamed = (config['ignore_unnamed'] == 's') or false -- copy unnamed parameter to named parameterlocal lastunnamed = 0if not(ignore_unnamed) and cfg.unnamed_parameter[config.CitationClass] thenfor i, v in ipairs(cfg.unnamed_parameter[config.CitationClass]) doif pframe.args[i] thenlocal args_value = mw.text.trim(pframe.args[i])if args_value ~= "" thenargs[v] = args_valueendlastunnamed = ielsebreakendendendfor k, v in pairs( pframe.args ) doif v ~= '' thenif not validate( k ) thenerror_text = "";if type( k ) ~= 'string' then-- Exclude empty numbered parametersif v:match("%S+") ~= nil and tonumber(k) > lastunnamed and lastunnamed > 0 thenerror_text, error_state = set_error( 'text_ignored', {v}, true );endelseif validate( k:lower() ) thenerror_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true );elseif #suggestions == 0 thensuggestions = mw.loadData('Modulo:Citazione/Suggerimenti');--suggestions = load_configuration_table( 'Modulo:Citazione/Suggerimenti');endif suggestions[ k:lower() ] ~= nil thenerror_text, error_state = set_error( 'parameter_ignored_suggest', {k, suggestions[ k:lower() ]}, true );elseerror_text, error_state = set_error( 'parameter_ignored', {k}, true );endendif error_text ~= '' thentable.insert( z.message_tail, {error_text, error_state} );endendargs[k] = v;elseif args[k] ~= nil thenargs[k] = v;endend-- hack per l'uso che fanno cita google books e youtube del parametro idif args.id and args.id~='' thenif in_array(config.CitationClass, {"googlebooks", "video"}) thenargs.id = nilendendreturn citation0( config, args )end-- Funzione per generare direttamente una citazione da un altro modulofunction z.cita_da_modulo(classe, args)-- mi assicuro che le code messaggi di errore siano vuote per evitare problemi in caso-- per citazioni multiple dall'interno dello stesso moduloz.error_categories = {}; -- lista delle categorie di errorez.error_ids = {}; -- lista dei codici di errorez.message_tail = {}; -- messaggi di errore da visualizzare in coda alla citazionereturn citation0( {CitationClass = classe}, args )end-- Elenco i formati di documenti gestitifunction z.list_external_links(frame)local rows = {'{| class = "wikitable sortable"\n!codice!!Testo popup'}local keys = {}for key, _ in pairs(cfg.external_link_type) dokeys[#keys+1] = keyendtable.sort(keys)for _,key in ipairs(keys) dorows[#rows+1] = mw.ustring.format('|-\n|%s||%s', key, cfg.external_link_type[key].text)endrows[#rows+1] = "|}"return table.concat(rows, '\n')end-- per formati esterni da altri templatefunction z.format(frame)local getArgs = require('Module:Arguments').getArgslocal args = getArgs(frame, {frameOnly = true})return get_format(args[1])endreturn z