Différences entre les versions de « Module:Biblio/Commun »

De Wikirouge
Aller à la navigation Aller à la recherche
(Page créée avec « -- Les fonctions du module Biblio/Commun sont des éléments nécessaire au modules Biblio/Ouvrage, Biblio/Article, Biblio/Lien web. local Commun = {} local Date = requ... »)
 
(Une version intermédiaire par le même utilisateur non affichée)
Ligne 6 : Ligne 6 :
 
local Date = require( 'Module:Date' )
 
local Date = require( 'Module:Date' )
 
local Outils = require( 'Module:Outils' )
 
local Outils = require( 'Module:Outils' )
local TableBuilder = require( 'Module:TableBuilder' )
 
 
local Langue -- = require( 'Module:Langue' ) ne sera chargé que si nécessaire
 
local Langue -- = require( 'Module:Langue' ) ne sera chargé que si nécessaire
 
local Languedata -- = mw.loadData( 'Module:Langue/Data' ) ne sera chargé que si nécessaire
 
local Languedata -- = mw.loadData( 'Module:Langue/Data' ) ne sera chargé que si nécessaire
Ligne 42 : Ligne 41 :
 
function Commun.validTextArg( args, name, ... )
 
function Commun.validTextArg( args, name, ... )
 
local texte = args[name]
 
local texte = args[name]
if type( texte ) == 'string' and texte ~= '' and texte:match( '%S' ) then
+
if type( texte ) == 'string' and texte ~= '' then
 
return texte
 
return texte
 
elseif #{ ... } > 0 then
 
elseif #{ ... } > 0 then
Ligne 74 : Ligne 73 :
 
Commun.numeros = abr{ 'n<sup>os</sup>', 'numéros', nbsp='+' }
 
Commun.numeros = abr{ 'n<sup>os</sup>', 'numéros', nbsp='+' }
 
Commun.page =  abr{ 'p.', 'page(s)', nbsp='+' }
 
Commun.page =  abr{ 'p.', 'page(s)', nbsp='+' }
Commun.plume = '<span class=nowrap title="Ouvrage utilisé pour la rédaction de l\'article">\194\160[[Image:Nuvola apps ksig horizonta.png|30px|link=|alt=]]</span>'
 
 
Commun.premiere = abr{ '1<sup>re</sup>', 'première' }
 
Commun.premiere = abr{ '1<sup>re</sup>', 'première' }
 
Commun.reimpr = abr{ 'réimpr.', 'réimpression', nbsp='+' }
 
Commun.reimpr = abr{ 'réimpr.', 'réimpression', nbsp='+' }
Ligne 128 : Ligne 126 :
 
-- voir Modèle:Module biblio/span initial
 
-- voir Modèle:Module biblio/span initial
 
function Commun.spanInitial( args, validArg )
 
function Commun.spanInitial( args, validArg )
local validArg = function ( ... ) return Commun.validTextArg( args, ... ) or false end
+
local id = validArg( 'id' )
local id, id2 = validArg( 'id' )
+
local id2
  
 
if id then
 
if id then
Ligne 136 : Ligne 134 :
 
local nom = validArg( 'nom1', 'nom', 'last1', 'last', 'author' )
 
local nom = validArg( 'nom1', 'nom', 'last1', 'last', 'author' )
 
local prenom = validArg( 'prénom1', 'prénom', 'firt1', 'first' )
 
local prenom = validArg( 'prénom1', 'prénom', 'firt1', 'first' )
local postnom = validArg('postnom1', 'postnom' )
+
local postnom = validArg( 'postnom1', 'postnom' )
 
local auteur_i = validArg( 'auteur1', 'author1', 'auteur' )
 
local auteur_i = validArg( 'auteur1', 'author1', 'auteur' )
 
local i = 1
 
local i = 1
Ligne 149 : Ligne 147 :
 
break
 
break
 
end
 
end
local a1, a2, a3 = string.match( auteur_i, '^([^ ]+) ?([^ ]*) ?(.*)$' )
+
local a1, a2, a3 = string.match( auteur_i, '^([^ ]+) *([^ ]*) *(.*)$' )
if Outils.notEmpty( a3 ) then
+
if a3 ~= '' then
 
local a2len = mw.ustring.len( a2 )
 
local a2len = mw.ustring.len( a2 )
 
if a2len == 1 or ( a2len == 2 and mw.ustring.sub( a2, -1 ) == "." ) then
 
if a2len == 1 or ( a2len == 2 and mw.ustring.sub( a2, -1 ) == "." ) then
Ligne 163 : Ligne 161 :
 
nom = a2 .. ' ' .. a3
 
nom = a2 .. ' ' .. a3
 
end
 
end
elseif Outils.notEmpty( a2 ) then
+
elseif a2 ~= '' then
 
-- a1 prénom, a2 nom
 
-- a1 prénom, a2 nom
 
nom = a2
 
nom = a2
Ligne 210 : Ligne 208 :
 
args['année'] = annee
 
args['année'] = annee
 
if d.mois then
 
if d.mois then
args.mois = validArg ('mois' ) or tostring( d.mois )
+
args.mois = validArg( 'mois' ) or tostring( d.mois )
 
end
 
end
 
if d.jour then
 
if d.jour then
args.jour = validArg ('jour' ) or tostring( d.jour )
+
args.jour = validArg( 'jour' ) or tostring( d.jour )
 
end
 
end
 
elseif mw.ustring.find( annee, "%a" ) and annee:find( "%f[%d]%d%d%d%d%f[%D][a-h]?" ) then
 
elseif mw.ustring.find( annee, "%a" ) and annee:find( "%f[%d]%d%d%d%d%f[%D][a-h]?" ) then
-- le [a-h]? final est destiné à accepter les lettres ajoutées lorsqu'il y a plusieurs ouvrage d'un même auteur la même année (cf. [[:en:Template:Harvard citation no brackets#More than one work in a year]])
+
-- le [a-h]? final est destiné à accepter les lettres ajoutées lorsqu'il y a plusieurs ouvrages d'un même auteur la même année (cf. [[:en:Template:Harvard citation no brackets#More than one work in a year]])
 
annee = annee:match( "%f[%d]%d%d%d%d%f[%D][a-h]?" )
 
annee = annee:match( "%f[%d]%d%d%d%d%f[%D][a-h]?" )
 
end
 
end
Ligne 248 : Ligne 246 :
 
-- voir Modèle:Module biblio/libellé
 
-- voir Modèle:Module biblio/libellé
 
function Commun.libelle( args )
 
function Commun.libelle( args )
local lib = args['libellé'] or ''
+
local lib = args['libellé']
if lib ~= '' then
+
if lib and lib ~= '' then
lib = '<small>[' .. lib .. ']</small> '
+
return '<small>[' .. lib .. ']</small> '
 +
else
 +
return ''
 
end
 
end
return lib
 
 
end
 
end
  
 
-- voir Modèle:Commentaire biblio
 
-- voir Modèle:Commentaire biblio
 
function Commun.commentaire( args )
 
function Commun.commentaire( args )
if Outils.trim( args.commentaire ) then
+
if args.commentaire and args.commentaire ~= '' then
local a = '<div style="Margin-top:0.1em ;margin-left:2em; line-height:1.5; margin-bottom:0.5em;">'
+
local a = '<div style="margin-left:2em; line-height:1.5;">'
 
local b = '</div>'
 
local b = '</div>'
 
return a, args.commentaire, b
 
return a, args.commentaire, b
Ligne 271 : Ligne 270 :
 
Langue = require( 'Module:Langue' )
 
Langue = require( 'Module:Langue' )
  
-- on essaie le code de langue complet (nécessaire pour les langues avec plusieurs mot comme "grec ancien")
+
-- on essaie le code de langue complet (nécessaire pour les langues avec plusieurs mots comme "grec ancien")
 
local codeLangue = Langue.codeLangue2( lang )
 
local codeLangue = Langue.codeLangue2( lang )
  
Ligne 336 : Ligne 335 :
  
  
-- boucle sur chaque nom, assemble toutes les caractéristique et ajoute l'ensemble à la liste.
+
-- boucle sur chaque nom, assemble toutes les caractéristiques et ajoute l'ensemble à la liste.
 
while nom or auteur do
 
while nom or auteur do
  
Ligne 406 : Ligne 405 :
 
local liste = { }
 
local liste = { }
  
-- fonction qui teste l'existence d'un paramètre et insérere  dans liste une abréviation discrète suivi de ce paramètre
+
-- fonction qui teste l'existence d'un paramètre et insère dans liste une abréviation discrète suivie de ce paramètre
 
local function insertAbr( arg, abrev, texte )
 
local function insertAbr( arg, abrev, texte )
 
if arg then
 
if arg then
Ligne 422 : Ligne 421 :
 
if langueOriginale then
 
if langueOriginale then
 
if trad then
 
if trad then
trad = ' par ' .. trad
+
trad = ' par ' .. trad
 
else
 
else
 
trad = ''
 
trad = ''
Ligne 440 : Ligne 439 :
 
table.insert( liste, 'postface ' .. args.postface )
 
table.insert( liste, 'postface ' .. args.postface )
 
end
 
end
insertAbr( validArg( 'illustrateur' ), 'ill.', 'illustrations' )
+
insertAbr( validArg( 'illustrateur', 'illustrations' ), 'ill.', 'illustrations' )
insertAbr( validArg( 'photographe' ), 'photogr.', 'photographies' )
+
insertAbr( validArg( 'photographe', 'photographies' ), 'photogr.', 'photographies' )
 
if validArg( 'champ libre' ) then
 
if validArg( 'champ libre' ) then
 
table.insert( liste, args['champ libre'] )
 
table.insert( liste, args['champ libre'] )
Ligne 455 : Ligne 454 :
 
---
 
---
 
-- voir émule le modèle:Inscription date
 
-- voir émule le modèle:Inscription date
-- la détection des arguments permet d'utilisé la fonction depuis un modèle, depuis invoke, ou depuis une autre fonction.
+
-- la détection des arguments permet d'utiliser la fonction depuis un modèle, depuis invoke, ou depuis une autre fonction.
-- pour facilité l'écriture de lua, annee (sans accent) est accepté lors de l'appel depuis lua.
+
-- pour faciliter l'écriture de lua, annee (sans accent) est accepté lors de l'appel depuis lua.
 
function Commun.inscriptionDate( frame )
 
function Commun.inscriptionDate( frame )
 
local args = Outils.extractArgs( frame )
 
local args = Outils.extractArgs( frame )
local annee = Outils.notEmpty( args['année'], args.annee, args.year )
+
local annee = Commun.validTextArg( args, 'année', 'annee', 'year' )
 
if annee then
 
if annee then
 
if annee:match( '^%-?%d+$' ) then
 
if annee:match( '^%-?%d+$' ) then
-- si l'année est correctement renseigné, on essaye de trouver le mois
+
-- si l'année est correctement renseignée, on essaye de trouver le mois
local mois = Outils.notEmpty( args.mois, args.month, args.saison )
+
local mois = Commun.validTextArg( args, 'mois', 'month', 'saison' )
 
mois = string.lower( mois or '' )
 
mois = string.lower( mois or '' )
local jour = Outils.notEmpty( args.jour, args.day, args['quantième'] )
+
local jour = Commun.validTextArg( args, 'jour', 'day', 'quantième' )
local t, jma = Date.validationJourMoisAnnee( jour, mois, annee )
+
local t, jma = Date.validationJourMoisAnnee{ jour, mois, annee }
 
if t then
 
if t then
 
jma.nolinks = true
 
jma.nolinks = true
Ligne 474 : Ligne 473 :
 
table.insert( date, mois )
 
table.insert( date, mois )
 
table.insert( date, annee )
 
table.insert( date, annee )
return '<time class="nowrap" datevalue="' .. annee .. '">' .. table.concat( date, ' ' ) .. '</time>'
+
return '<time class="nowrap" datetime="' .. annee .. '">' .. table.concat( date, ' ' ) .. '</time>'
 
end
 
end
 
else
 
else
Ligne 480 : Ligne 479 :
 
end
 
end
 
else
 
else
-- si annee n'est pas précisé, on utilise la paramètre date
+
-- si annee n'est pas précisé, on utilise le paramètre date
local date = Outils.validTextArg( args, 'date' )
+
local date = Commun.validTextArg( args, 'date' )
 
if date then
 
if date then
 
date = date:lower()
 
date = date:lower()
 
-- Date iso avec l'heure : suppression de l'heure
 
-- Date iso avec l'heure : suppression de l'heure
date = date:gsub( '^(%d%d%d%d%-%d%d%-%d%d)t[%d:+-]+$', '%1')
+
date = date:gsub( '^(%d%d%d%d%-%d%d%-%d%d)t[%d:+-]+$', '%1' )
 
local t, jma = Date.separationJourMoisAnnee( date )
 
local t, jma = Date.separationJourMoisAnnee( date )
if t and ( Date.determinationMois( jma.mois ) or Date.valideSaison( jma.mois ) ) then
+
if t then
args['année'] = jma.annee
 
 
jma.nolinks = true
 
jma.nolinks = true
jma.nocat = true
 
 
return Date._modeleDate( jma )
 
return Date._modeleDate( jma )
 
else
 
else
 
-- date non reconnue, on essaye Month day, year
 
-- date non reconnue, on essaye Month day, year
 
local mois, jour, annee = mw.ustring.match( date, '^([%a]+)%s*(%d%d?)[,%s]+(%d+)$' )
 
local mois, jour, annee = mw.ustring.match( date, '^([%a]+)%s*(%d%d?)[,%s]+(%d+)$' )
local t, jma = Date.validationJourMoisAnnee( jour, mois, annee )
+
local t, jma = Date.validationJourMoisAnnee{ jour, mois, annee }
 
if annee and t then
 
if annee and t then
 
jma.nolinks = true
 
jma.nolinks = true
Ligne 507 : Ligne 504 :
 
end
 
end
  
-- retire toutes le lien interne, externe et balise html pour ne garder que le texte brut.
+
-- retire tous les liens internes, externes et balises html pour ne garder que le texte brut.
 
local function nettoyageTexte( texte )
 
local function nettoyageTexte( texte )
 
if type( texte ) == 'string'  then
 
if type( texte ) == 'string'  then
Ligne 514 : Ligne 511 :
 
return ( t ~= '' and t ) or l
 
return ( t ~= '' and t ) or l
 
end
 
end
-- nettoyage des liens interne
+
-- nettoyage des liens internes
 
texte = texte:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', texteDuLien )
 
texte = texte:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', texteDuLien )
 
-- nettoyage des liens externes
 
-- nettoyage des liens externes
 
:gsub( '%[https?://[^%[%] ]* *([^%]]+)%]', '%1' )
 
:gsub( '%[https?://[^%[%] ]* *([^%]]+)%]', '%1' )
 
:gsub( '%[//[^%[%] ]* *([^%]]+)%]', '%1' )
 
:gsub( '%[//[^%[%] ]* *([^%]]+)%]', '%1' )
-- nettoyage des balise html
+
-- nettoyage des balises html
 
:gsub( '%b<>', '' )
 
:gsub( '%b<>', '' )
 
end
 
end
Ligne 566 : Ligne 563 :
 
insertList( 'rft.place', texteLien( validArg( 'lieu', 'location' ) ), nil )
 
insertList( 'rft.place', texteLien( validArg( 'lieu', 'location' ) ), nil )
 
insertList( 'rft.pub', texteLien( validArg( 'éditeur', 'édition' ) ), nil )
 
insertList( 'rft.pub', texteLien( validArg( 'éditeur', 'édition' ) ), nil )
insertList( 'rft.edition', args["numéro d'édition"] )
+
insertList( 'rft.edition', texteLien( validArg( "numéro d'édition", "numéro édition" ) ), nil )
 
end
 
end
 
insertList( 'rft.stitle', args['sous-titre'] )
 
insertList( 'rft.stitle', args['sous-titre'] )
Ligne 640 : Ligne 637 :
 
local contextObject = table.concat( liste, '&' )
 
local contextObject = table.concat( liste, '&' )
  
-- calcul d'un id pour que le span vide ne soit pas supprimé par tydy ( cf. https://bugzilla.wikimedia.org/show_bug.cgi?id=27786 )
+
return '<span class="Z3988" title="' .. contextObject .. '"></span>'
local id=0
 
for i = 1, #contextObject do
 
id = id + string.byte( contextObject, i )
 
end
 
 
 
return '<span class="Z3988" title="' .. contextObject .. '" id="COinS_' .. id ..'"></span>'
 
 
end
 
end
  
  
 
return Commun
 
return Commun

Version du 5 novembre 2020 à 00:06

1 Utilisation

Ce module est destiné à être utilisé par les autres modules biblios, et ne fournit aucune fonction directement utilisable depuis l'espace modèle.

1.1 Fonctions Utilisables depuis un autre module

1.1.1 Constantes

Parfois suivies ou précédé d'un espace insécable ici remplacé par « _ ».

  • chap : chap._ ;
  • coll : coll._ ;
  • ed : _éd. ;
  • nbp : _p. ;
  • numero : no_ ;
  • numeros : nos_ ;
  • page : p._ ;
  • premiere : 1re ;
  • reimpr : réimpr._ ;
  • tome : t._ ;
  • vol : vol._ ;

1.1.2 fonctions

  • detailEdition( ref ) – affiche « [détail de l’édition] ».
  • detailEditions( ref ) – affiche « [détail des éditions] ».
  • romain( texte ) – affiche le texte en capitales.
  • spanInitial( args, validArg ) – crée un span de class ouvrage avec un id correspondant aux quatre premiers noms et à l'année.
  • libelle( args ) – affiche en <small> et entre crochet le paramètre libellé.
  • commentaire( args ) – affiche le paramètre commentaire dans un <div>.
  • indicationDeLangue( args, validArg ) – affiche un ou plusieurs indicateur de langue type (en) en fonction du contenu du paramètre langue. Ignore le français s'il est seul.
  • responsabilitePrincipale( args, validArg ) – affiche la liste des auteurs avec leur responsabilité.
  • responsabiliteSecondaire( args, validArg ) – affiche entre parenthèse traducteur, illustrateur, photographe...
  • Commun.COinS( args, validArg, genre ) – génère un « Context Object in Span », suivant la norme ANSI Z39.88-2004

1.2 fonctions internes

  • nettoyageTexte( texte ) – retourne le texte sans lien interne, externe ni balise Html.

1.3 Modules externes et autres éléments dont ce module a besoin pour fonctionner



-- Les fonctions du module Biblio/Commun sont des éléments nécessaire au modules Biblio/Ouvrage, Biblio/Article, Biblio/Lien web.

local Commun = {}


local Date = require( 'Module:Date' )
local Outils = require( 'Module:Outils' )
local Langue -- = require( 'Module:Langue' ) ne sera chargé que si nécessaire
local Languedata -- = mw.loadData( 'Module:Langue/Data' ) ne sera chargé que si nécessaire


--[=[
	Trouve le premier lien interwiki '[[lien|texte]]' de str et retourne : texte, lien
	Si le lien est '[[texte]]', retourne : texte, texte.
	Si str ne contient pas de lien interwiki, retourne : str (et nil)
	Les fichiers et images ne sont pas considérés comme des liens.
	Si str n'est pas une chaine, retourne : nil
]=]
local function texteLien( str )
	if type( str ) == 'string' then
		for lien, texte in string.gmatch( str, '%[%[ *([^%[%]|]*)|? *([^%[%]]*)%]%]' ) do
			texte = ( texte ~= '' and texte ) or lien or str
			if not lien then
				return str
			end
			local testlien = string.lower( lien )
			local fichier = string.match( testlien, '^fichier:' ) 
				or  string.match( testlien, '^image:' )
				or  string.match( testlien, '^file:' )
			if not fichier then 
				return texte, lien
			end
		end
		return str
	end
end


-- Copie de Outils.validTextArg sans trim, pour performances avec les paramètres nommés ?
-- refs [[Spécial:Diff/105796198]]
function Commun.validTextArg( args, name, ... )
	local texte = args[name]
	if type( texte ) == 'string' and texte ~= '' then
		return texte
	elseif #{ ... } > 0 then
		return Commun.validTextArg( args, ... )
	end
end


--[[
	Génère une abréviation discrète
	paramètres : 
		1 = abréviation,
		2 = texte,
		nbsp = '-' pour une espace insécable avant l'abréviation, '+' pour l'avoir après.
]]
local function abr( args )
	return ( args.nbsp == '-' and '&nbsp;' or '' )
		.. '<abbr class="abbr" title="' .. args[2] .. '">'
		.. args[1]
		.. '</abbr>'
		.. ( args.nbsp == '+' and '&nbsp;' or '' )
end


-- Abréviation utiles
Commun.chap =   abr{ 'chap.', 'chapitre(s)', nbsp='+' }
Commun.coll =   abr{ 'coll.', 'collection', nbsp='+' }
Commun.ed =     abr{ 'éd.', 'édition', nbsp='-' }
Commun.nbp =    abr{ 'p.', 'pages', nbsp='-' }
Commun.numero = abr{ 'n<sup>o</sup>', 'numéro', nbsp='+' }
Commun.numeros = abr{ 'n<sup>os</sup>', 'numéros', nbsp='+' }
Commun.page =   abr{ 'p.', 'page(s)', nbsp='+' }
Commun.premiere = abr{ '1<sup>re</sup>', 'première' }
Commun.reimpr = abr{ 'réimpr.', 'réimpression', nbsp='+' }
Commun.tome = abr{ 't.', 'tome', nbsp='+' }
Commun.vol = abr{ 'vol.', 'volume', nbsp='+' }


function Commun.detailEdition( ref )
	return '<small>&#91;[[' .. ref .. '|détail de l’édition]]&#93;</small>'
end

function Commun.detailEditions( ref )
	return '<small>&#91;[[' .. ref .. '|détail des éditions]]&#93;</small>'
end


-- affiche le texte en nombre romain majuscule.
function Commun.romain( texte )
    local a = '<span class="romain" style="text-transform:uppercase">'
    local b = '</span>'
    return a, texte, b
end

function Commun.fusionTexteLien( texte, lien, categ )
	local categorisation, result
	local message = '<sup style="color:red;">[le lien externe a été retiré]</sup>'
	if lien and lien ~= '' then
		if texte:match( '%[%[' ) then
			result = Commun.fusionTexteLien( texte, nil, categ )
		elseif lien:match( '^http' ) or lien:match( '//' ) then
			lien = false
			categorisation = true
			result = texte .. message
		else
			result = string.format( '[[%s|%s]]', lien, texte )
		end
	else
		--[=[ if texte:match( '//' ) then
			result = texte:gsub( '%[https?://[^%[%] ]* *([^%]]+)%]', '%1' )
								:gsub( '%[//[^%[%] ]* *([^%]]+)%]', '%1' )
			if result ~= texte then
				result = result .. message
				categorisation = true
			end
		end ]=] -- désactivé pour le moment (peut être activé si quelqu'un est prêt à corriger les erreurs)
	end
	if categorisation and type( categ ) == 'table' then
		categ.lienExterne = true
	end
	return result or texte
end

-- voir Modèle:Module biblio/span initial
function Commun.spanInitial( args, validArg )
	local id = validArg( 'id' )
	local id2

	if id then
		id = ' id="' .. id .. '"'
	else
		local nom = validArg( 'nom1', 'nom', 'last1', 'last', 'author' )
		local prenom = validArg( 'prénom1', 'prénom', 'firt1', 'first' )
		local postnom = validArg( 'postnom1', 'postnom' )
		local auteur_i = validArg( 'auteur1', 'author1', 'auteur' )
		local i = 1
		local idTab, id2Tab = { }, { }

		while nom or auteur_i do
			if auteur_i and not nom then
				-- tentative de séparation de l'auteur en prénom nom.
				-- Enregistre le résultat dans args pour les COinS.
				auteur_i = texteLien( auteur_i )
				if auteur_i == '' then
					break
				end
				local a1, a2, a3 = string.match( auteur_i, '^([^ ]+) *([^ ]*) *(.*)$' )
				if a3 ~= '' then
					local a2len = mw.ustring.len( a2 )
					if a2len == 1 or ( a2len == 2 and mw.ustring.sub( a2, -1 ) == "." ) then
						-- a1 est le prénom, a2 une initiale et a3 le nom
						nom = a3
						if i == 1 then
							args.nom = a3
							args['prénom'] = a1 .. ' ' .. a2
						end
					else
						-- a2 peut être le deuxième prénon ou le début du nom
						nom = a2 .. ' ' .. a3
					end
				elseif a2 ~= '' then
					-- a1 prénom, a2 nom
					nom = a2
					if i == 1 then
						args.nom = a2
						args['prénom'] = a1
					end
				else
					nom = a1
				end
			end
			if not auteur_i then
				if prenom and postnom then
					auteur_i = prenom .. ' ' .. nom .. ' ' .. postnom
				elseif prenom then
					auteur_i = prenom .. ' ' .. nom
				elseif postnom then
					auteur_i = nom .. ' ' .. postnom
				else
					auteur_i = nom
				end
			end
			table.insert( idTab, mw.uri.anchorEncode( nom ) )
			table.insert( id2Tab, mw.uri.anchorEncode( auteur_i ) )

			if i == 4 then
				break
			end
			i = i + 1
			nom = validArg( 'nom' .. i, 'last' .. i )
			prenom = validArg( 'prénom' .. i, 'first' .. i )
			postnom = validArg( 'postnom' .. i)
			auteur_i = validArg( 'auteur' .. i, 'author' .. i )
		end

		if #idTab < 4 and validArg( 'auteur institutionnel' ) then
			table.insert( idTab, mw.uri.anchorEncode( validArg( 'auteur institutionnel' ) ) )
			table.insert( id2Tab, idTab[#idTab] )
		end

		local annee = validArg( 'année', 'year', 'date' )
		if annee then
			local t, d = Date.separationJourMoisAnnee( annee )
			if t and d.annee and annee ~= d.annee then
				annee = tostring( d.annee )
				args['année'] = annee
				if d.mois then
					args.mois = validArg( 'mois' ) or tostring( d.mois )
				end
				if d.jour then
					args.jour = validArg( 'jour' ) or tostring( d.jour )
				end
			elseif mw.ustring.find( annee, "%a" ) and annee:find( "%f[%d]%d%d%d%d%f[%D][a-h]?" ) then
				-- le [a-h]? final est destiné à accepter les lettres ajoutées lorsqu'il y a plusieurs ouvrages d'un même auteur la même année (cf. [[:en:Template:Harvard citation no brackets#More than one work in a year]])
				annee = annee:match( "%f[%d]%d%d%d%d%f[%D][a-h]?" )
			end
			annee = mw.uri.anchorEncode( tostring( annee ) )
			table.insert( idTab, annee )
			table.insert( id2Tab, annee )
		end

		if #idTab > 0 then
			id = ' id="' .. table.concat( idTab ) .. '"'
			id2 = ' id="' .. table.concat( id2Tab ) .. '"'
			if id2 == id then
				id2 = false
			end
		else
			id = ''
		end
	end

	local spaninitial, spanfinal
	if id2 then
		spaninitial = '<span class="ouvrage"' .. id .. '><span class="ouvrage"' .. id2 .. '>'
		spanfinal = '</span></span>'
	else
		spaninitial = '<span class="ouvrage"' .. id .. '>'
		spanfinal = '</span>'
	end
	return spaninitial, spanfinal
end

-- voir Modèle:Module biblio/libellé
function Commun.libelle( args )
	local lib = args['libellé']
	if lib and lib ~= '' then
		return '<small>[' .. lib .. ']</small> '
	else
		return ''
	end
end

-- voir Modèle:Commentaire biblio
function Commun.commentaire( args )
	if args.commentaire and args.commentaire ~= '' then
		local a = '<div style="margin-left:2em; line-height:1.5;">'
		local b = '</div>'
		return a, args.commentaire, b
	end
	return ''
end

-- voir Modèle:Module biblio/indication de langue
function Commun.indicationDeLangue( args, validArg )
	local lang = validArg( 'langue', 'lang', 'lien langue', 'language' )
	if lang then
		Langue = require( 'Module:Langue' )

		-- on essaie le code de langue complet (nécessaire pour les langues avec plusieurs mots comme "grec ancien")
		local codeLangue = Langue.codeLangue2( lang )

		if codeLangue == 'fr' or codeLangue:sub(1, 3) == 'fr-' then
			return ''
		elseif codeLangue ~= '' then
			return Langue.indicationMultilingue{ codeLangue }, codeLangue
		end

		-- si la langue n'a pas été trouvée on considère qu'il y a plusieurs langues
		-- séparation des langues s'il y en a plusieurs
		local listeLangue = mw.text.split( lang, '[+,;:/ %.]+' )

		-- code langue principal qui sera appliqué aux titres
		codeLangue = Langue.codeLangue2( listeLangue[1] )

		if codeLangue == '' then
			if type( args.categ ) == 'table' then
				args.categ.langue = true
			end
			return Langue.indicationMultilingue( listeLangue )
		else
			-- calcul code de langue et catégorie
			local indicationLangue = Langue.indicationMultilingue( listeLangue )
			if type( args.categ ) == 'table' then
				args.categ.langue = indicationLangue:find( '???', 1, true )
			end

			if codeLangue ~= 'fr' and codeLangue:sub(1, 3) ~= 'fr-' then
				return indicationLangue, codeLangue
			elseif #listeLangue > 1 then
				return indicationLangue, codeLangue
			end
		end
	end
	return ''
end


-- voir Modèle:Module biblio/responsabilité principale
function Commun.responsabilitePrincipale( args, validArg )

	local nom = validArg( 'nom1', 'nom', 'last1', 'last' )
	local auteur = validArg( 'auteur1', 'auteur', 'author1', 'author' )
	local auteurInstitutionnel = validArg( 'auteur institutionnel' )
	if not ( nom or auteur or auteurInstitutionnel ) then
		return ''
	end

	if nom or auteur then
		-- clarification des paramètres
		args['prénom1'] = validArg( 'prénom1', 'prénom', 'first1', 'first' )
		args['postnom1'] = validArg( 'postnom1', 'postnom' )

		args.directeur1 = validArg( 'directeur1', 'directeur' )
		args['lien auteur1'] = validArg( 'lien auteur1', 'lien auteur', 'author-link' )
	end

	-- préparation des variables
	local listeRresponsables = { }  -- contiendra un élément pour chaque nom
	local directeur = abr { 'dir.', 'directeur de publication' }
	local prenom, postnom, dir, responsable, lien, precision, resp
	local i = 1


	-- boucle sur chaque nom, assemble toutes les caractéristiques et ajoute l'ensemble à la liste.
	while nom or auteur do

		-- nom de l'auteur
		if not auteur then
			prenom = validArg( 'prénom' .. i, 'first' .. i )
			nom = '<span class="nom_auteur">' .. nom .. '</span>'
			postnom = validArg( 'postnom' .. i)
			if prenom and postnom then
				auteur = prenom .. ' ' .. nom .. ' ' .. postnom
			elseif prenom then
				auteur = prenom .. ' ' .. nom
			elseif postnom then
				auteur = nom .. ' ' .. postnom
			else
				auteur = nom
			end
		end

		-- lien sur l'auteur
		auteur = Commun.fusionTexteLien( auteur, args['lien auteur' .. i], args.categ)

		-- définition des responsabilités
		dir = validArg( 'directeur' .. i )
		resp = validArg( 'responsabilité' .. i )
		if dir then
			if resp then
				precision = ' (' .. directeur .. ' et ' .. resp .. ')'
			else
				precision = ' (' .. directeur .. ')'
			end
		elseif resp then
			precision = ' (' .. resp .. ')'
		else
			precision = ''
		end

		table.insert( listeRresponsables, auteur .. precision )

		i = i + 1
		nom = validArg( 'nom' .. i, 'last' .. i )
		auteur = validArg( 'auteur' .. i, 'author' .. i )
	end

	local listeAuteurs
	local et_al = ''
	if validArg( 'et al.', 'et alii' ) then
		et_al = " ''" .. abr { "et al.", "et alii (et d’autres)" } .. "''"
		listeAuteurs = table.concat( listeRresponsables, ', ' ) .. et_al
	else
		listeAuteurs = mw.text.listToText( listeRresponsables )
	end

	if auteurInstitutionnel then
		if #listeRresponsables > 0 then
			return listeAuteurs .. ', ' .. auteurInstitutionnel
		else
			return auteurInstitutionnel .. et_al
		end
	else
		return listeAuteurs
	end

end


-- voir Module biblio/responsabilité secondaire
function Commun.responsabiliteSecondaire( args, validArg )
	local liste = { }

	-- fonction qui teste l'existence d'un paramètre et insère dans liste une abréviation discrète suivie de ce paramètre
	local function insertAbr( arg, abrev, texte )
		if arg then
			table.insert( liste, abr{ abrev, texte, nbsp='+' } .. arg )
		end
	end

	-- langue originale et traducteur
	local trad = validArg( 'traducteur', 'trad', 'traduction' )
	local langueOriginale = validArg( 'langue originale' )
	if langueOriginale then
		local Languedata = mw.loadData( 'Module:Langue/Data' )
		langueOriginale = Languedata[langueOriginale] and Languedata[langueOriginale].nom
	end
	if langueOriginale then
		if trad then
			trad = ' par ' .. trad
		else
			trad = ''
		end
		if mw.ustring.sub( langueOriginale, 1, 1 ):match( '[a, e, é, è, i, o, u]' ) or
			langueOriginale == 'hébreu' then
			trad = "de l'" .. langueOriginale .. trad
		else
			trad = 'du ' .. langueOriginale .. trad
		end
	end
	insertAbr( trad, 'trad.', 'traduction' )

	-- ajout des différents responsables
	insertAbr( validArg( 'préface' ), 'préf.', 'préface' )
	if validArg( 'postface' ) then
		table.insert( liste, 'postface ' .. args.postface )
	end
	insertAbr( validArg( 'illustrateur', 'illustrations' ), 'ill.', 'illustrations' )
	insertAbr( validArg( 'photographe', 'photographies' ), 'photogr.', 'photographies' )
	if validArg( 'champ libre' ) then
		table.insert( liste, args['champ libre'] )
	end

	-- concaténation de l'ensemble
	local texte = table.concat( liste, ', ')
	if texte ~= '' then
		return ' (' .. texte .. ')'
	end
end

---
-- voir émule le modèle:Inscription date
-- la détection des arguments permet d'utiliser la fonction depuis un modèle, depuis invoke, ou depuis une autre fonction.
-- pour faciliter l'écriture de lua, annee (sans accent) est accepté lors de l'appel depuis lua.
function Commun.inscriptionDate( frame )
	local args = Outils.extractArgs( frame )
	local annee = Commun.validTextArg( args, 'année', 'annee', 'year' )
	if annee then
		if annee:match( '^%-?%d+$' ) then
			-- si l'année est correctement renseignée, on essaye de trouver le mois
			local mois = Commun.validTextArg( args, 'mois', 'month', 'saison' )
			mois = string.lower( mois or '' )
			local jour = Commun.validTextArg( args, 'jour', 'day', 'quantième' )
			local t, jma = Date.validationJourMoisAnnee{ jour, mois, annee }
			if t then
				jma.nolinks = true
				return Date._modeleDate( jma )
			else
				local date = { jour }
				table.insert( date, mois )
				table.insert( date, annee )
				return '<time class="nowrap" datetime="' .. annee .. '">' .. table.concat( date, ' ' ) .. '</time>'
			end
		else
			return Commun.inscriptionDate{ date = annee }
		end
	else
		-- si annee n'est pas précisé, on utilise le paramètre date
		local date = Commun.validTextArg( args, 'date' )
		if date then
			date = date:lower()
			-- Date iso avec l'heure : suppression de l'heure
			date = date:gsub( '^(%d%d%d%d%-%d%d%-%d%d)t[%d:+-]+$', '%1' )
			local t, jma = Date.separationJourMoisAnnee( date )
			if t then
				jma.nolinks = true
				return Date._modeleDate( jma )
			else
				-- date non reconnue, on essaye Month day, year
				local mois, jour, annee = mw.ustring.match( date, '^([%a]+)%s*(%d%d?)[,%s]+(%d+)$' )
				local t, jma = Date.validationJourMoisAnnee{ jour, mois, annee }
				if annee and t then
					jma.nolinks = true
					return Date._modeleDate( jma )
				end
			end
			return date
		end
	end
	return ''
end

-- retire tous les liens internes, externes et balises html pour ne garder que le texte brut.
local function nettoyageTexte( texte )
	if type( texte ) == 'string'  then
		if texte:match( '[%[<]' ) then
			local function texteDuLien( l, t )
				return ( t ~= '' and t ) or l
			end
			-- nettoyage des liens internes
			texte = texte:gsub( '%[%[([^%[%]|]*)|?([^%[%]]*)%]%]', texteDuLien )
			-- nettoyage des liens externes
				:gsub( '%[https?://[^%[%] ]* *([^%]]+)%]', '%1' )
				:gsub( '%[//[^%[%] ]* *([^%]]+)%]', '%1' )
			-- nettoyage des balises html
				:gsub( '%b<>', '' )
		end
		return texte
	end
end

-- voir Modèle:COinS bibliographique
-- NISO Z39.88
-- http://www.openurl.info/registry
function Commun.COinS( args, validArg, genre )
	local liste = { }

	-- insertlist ajoute à la table 'liste' un couple 'nom Coins normalisé' - 'donnée'
	-- Si istexte = true, le deuxième élément de tab est considéré comme du texte,
	-- sinon comme le nom d'un paramètre.
	local function insertList( key, value, prefix )
		prefix = prefix or ''
		if type( value ) == 'string' and value ~= '' then
			table.insert( liste, key .. '=' .. mw.uri.encode( prefix .. value ) )
		end
	end

	-- norme du COinS
	insertList( 'ctx_ver', 'Z39.88-2004' )

	-- genre, titre et sous-titre
	if genre == 'article' then
		insertList( 'rft_val_fmt', 'info:ofi/fmt:kev:mtx:journal' )
		insertList( 'rft.genre', 'article' )
		insertList( 'rft.atitle', nettoyageTexte( args.titre ) )
		insertList( 'rft.jtitle', nettoyageTexte( validArg( 'périodique', 'revue', 'journal' ) ) )
		insertList( 'rft.issue', validArg( 'numéro', 'no', 'issue' ) )
	else
		-- genre = ouvrage ou chaitre
		insertList( 'rft_val_fmt','info:ofi/fmt:kev:mtx:book' )
		if genre == 'chapitre' then
			insertList( 'rft.genre', 'bookitem' )
		else
			insertList( 'rft.genre', 'book' )
		end
		insertList( 'rft.btitle', nettoyageTexte( args.titre ) )
		insertList( 'rft.atitle', nettoyageTexte( validArg( 'titre chapitre', 'titreChap' ) ) )

		-- donnée sur l'éditeur
		insertList( 'rft.place', texteLien( validArg( 'lieu', 'location' ) ), nil )
		insertList( 'rft.pub', texteLien( validArg( 'éditeur', 'édition' ) ), nil )
		insertList( 'rft.edition', texteLien( validArg( "numéro d'édition", "numéro édition" ) ), nil )
	end
	insertList( 'rft.stitle', args['sous-titre'] )

	-- Premier auteur, séparé en noms et prénoms
	local nom = texteLien( validArg( 'nom1', 'nom', 'last1', 'last' ) )
	if nom then
		insertList( 'rft.aulast', nom )
		insertList( 'rft.aufirst', validArg( 'prénom1', 'prénom', 'first1', 'first' ) )
		insertList( 'rtf.ausuffix ', validArg( 'postnom1', 'postnom' ) )
	else
		local auteur = texteLien( validArg( 'auteur', 'auteur1' ) )
		if auteur then
			insertList( 'rft.au', auteur )
		end
	end

	-- les autres auteurs, la norme ne prévoit pas de séparation
	for i = 2, 20 do
		local nom_i = texteLien( validArg( 'nom' .. i ) )
		if nom_i then
			local prenom_i = validArg( 'prénom' .. i )
			local postnom_i = validArg( 'postnom' .. i)
			if prenom_i and postnom_i then
				insertList( 'rft.au', nom_i .. ' ' .. postnom_i .. ', ' .. prenom_i )
			elseif prenom_i then
				insertList( 'rft.au', nom_i .. ', ' .. prenom_i )
			elseif postnom_i then
				insertList( 'rft.au', nom_i .. ' ' .. postnom_i )
			else
				insertList( 'rft.au', nom_i )
			end
		else
			local auteur_i = texteLien( validArg( 'auteur' .. i ) )
			if auteur_i then
				insertList( 'rft.au', auteur_i )
			else
				break
			end
		end
	end

	if validArg( 'auteur institutionnel' ) then
		insertList( 'rft.aucorp', args['auteur institutionnel'] )
	end

	-- date
	local datePub = Date.dateISO( args )
	if datePub then
		insertList( 'rft.date', datePub )
	else
		insertList( 'rft.date', args.date )
	end

	-- doonées physique de la publication
	insertList( 'rft.volume', validArg( 'volume', 'vol' ) )
	insertList( 'rft.pages', validArg( 'passage', 'page' ) )
	insertList( 'rft.spage', args['page début chapitre'] )
	insertList( 'rft.tpages', args['pages totales'] )


	-- références internationales
	insertList( 'rft.isbn', args.isbn )
	insertList( 'rft.issn', args.issn )
	insertList( 'rft_id', args.doi, 'info:doi/' )
	insertList( 'rft_id', args.pmid, 'info:pmid/' )
	insertList( 'rft_id', args.oclc, 'info:oclcnum/' )
	insertList( 'rft_id', args.url )

	-- referer : page Wikipedia ou se trouve cette référence
	insertList( 'rfr_id', 'fr.wikipedia.org:' .. mw.title.getCurrentTitle().fullText, 'info:sid/' )

	local contextObject = table.concat( liste, '&' )

	return '<span class="Z3988" title="' .. contextObject .. '"></span>'
end


return Commun