Module:Italiques biologiques

La documentation pour ce module peut être créée à Module:Italiques biologiques/doc

-- gestion de la mise en italique d'un nom scientifique, en respectant les conventions de la biologie

local p = {}

-- fonction basique mettant le titre courant en italique, sauf la partie namespace et la partie homonymie si présente
-- paramètres : lang → optionnel : ajout d'un tag de langue si présent
function p.titre_en_italiques(frame)

    local titre = mw.title.getCurrentTitle() -- l'objet titre pour la page courante
    local resu  -- le résultat qui sera retourné
    local page = titre.text  -- le nom de la page, sans le namespace
    -- paramètre optionnel : la langue
    local lang = frame.args["lang"] or frame:getParent().args["lang"]

    -- variables contenant l'ouverture et la fermeture du span (ou vide)
    local ospan = ""
    local fspan = ""
    if (lang) then
        ospan = '<span lang="' .. lang .. '">'
        fspan = '</span>'
    end
    
    -- préparation résultat : on commence par le namespace
    if (titre.nsText ~= "") then
        resu = titre.nsText .. ":"
    end
    -- on ajoute le span de la langue si demandé
    resu = resu .. ospan
    -- on ajoute l'italique
    resu = resu .. "''"
    if (mw.ustring.find(page, " (", 1, true)) then
        -- présence d'une homonymie, on ajoute la fin des italiques
        -- avant le " (" (une seule fois, au cas où il y aurait plusieurs ())
        -- on ajoute aussi la fermeture éventuelle du span
        resu = resu .. mw.ustring.gsub(page, " [(]", "''" .. fspan .. " (", 1)
    else
        -- pas d'homonymie, on ajoute la page + la fin de l'italique + fin du span
        resu = resu .. page .. "''" .. fspan
    end
    -- résultat, dans un preprocess afin d'interpréter son action
    return frame:preprocess("{{DISPLAYTITLE:" .. resu .. "|noerror}}")
end

-- retourne le texte après avoir supprimer les espaces, retour ligne... en début et fin de texte.
-- si texte == nil, la fonction retourne nil. 
-- Si le texte est vide ou composé uniquement d'espces, la fonction retourne un texte vide ''.
function p.trim (texte)
    return texte and string.match (texte, '^%s*(.-)%s*$')
end

-- table des éléments à ne pas mettre en italique
-- note : mettre un " " avant un terme qui existe aussi sous forme longue
--  exemple : " var.", à cause de "convar.". Sans l'espace les deux vont s'appliquer
--            au texte analysé. Notez de bien répercuter ce même espace dans la partie de droite
p.exclude = {
    { " cl[.]", " ''cl.''" },
    { "convar[.]", "''convar.''" },
    { "f[.]sp[.]", "''f.sp.''" },
    { " f[.]", " ''f.''" },
    { " gen[.]", " ''gen.''" },
    { "kl[.]", "''kl.''" },
    { "nothog[.]", "''nothog.''" },
    { "nothosp[.]", "''nothosp.''" },
    { "nothovar[.]", "''nothovar.''" },
    { " ord[.]", " ''ord.''" },
    { " fam[.]", " ''fam.''" },
    { " sect[.]", " ''sect.''" },
    { " ser[.]", " ''ser.''" },
    { " sp[.]", " ''sp.''" },
    { "subg[.]", "''subg.''" },
    { "subsp[.]", "''subsp.''" },
    { "Groupe", "''Groupe''" },
    { " tr[.]", " ''tr.''" },
    { " var[.]", " ''var.''" },
    { "×", "''×''" },
    { "[(]", "''(''" },
    { "[)]", "'')''" },
    { "pv", "''pv''" },
    { "pathovar", "''pathovar''" },
    { "morphovar", "''morphovar''" },
    { "phagovar", "''phagovar''" },
    { "serovar", "''serovar''" },
    { "chemovar", "''chemovar''" },
    { "cultivar", "''cultivar''" },
    { "chemoform", "''chemoform''" },
    { "chemotype", "''chemotype''" },
    { "morphotype", "''morphotype''" },
    { "pathotype", "''pathotype''" },
    { "phagotype", "''phagotype''" },
    { "lysotype", "''lysotype''" },
    { " phase ", " ''phase'' " },
    { "serotype", "''serotype''" },
    { " state ", " ''state'' " },
    { "forma specialis", "''forma specialis''" }
}
-- liste d'exclusion uniquement pour mettre droit dans la partie {{taxobox}} italique (ifgenre)
p.exclude_span = {
    { " cl[.]", " <span style=\"font-style: normal\">cl.</span>" },
    { "convar[.]", "<span style=\"font-style: normal\">convar.</span>" },
    { " f[.]", " <span style=\"font-style: normal\">f.</span>" },
    { " gen[.]", " <span style=\"font-style: normal\">gen.</span>" },
    { "kl[.]", "<span style=\"font-style: normal\">kl.</span>" },
    { "nothog[.]", "<span style=\"font-style: normal\">nothog.</span>" },
    { "nothosp[.]", "<span style=\"font-style: normal\">nothosp.</span>" },
    { "nothovar[.]", "<span style=\"font-style: normal\">nothovar.</span>" },
    { " ord[.]", " <span style=\"font-style: normal\">ord.</span>" },
    { " fam[.]", " <span style=\"font-style: normal\">fam.</span>" },
    { " sect[.]", " <span style=\"font-style: normal\">sect.</span>" },
    { " ser[.]", " <span style=\"font-style: normal\">ser.</span>" },
    { " sp[.]", " <span style=\"font-style: normal\">sp.</span>" },
    { "subg[.]", "<span style=\"font-style: normal\">subg.</span>" },
    { "subsp[.]", "<span style=\"font-style: normal\">subsp.</span>" },
    { "Groupe", "<span style=\"font-style: normal\">Groupe</span>" },
    { " tr[.]", " <span style=\"font-style: normal\">tr.</span>" },
    { " var[.]", " <span style=\"font-style: normal\">var.</span>" },
    { "×", "<span style=\"font-style: normal\">×</span>" },
    { "[(]", "<span style=\"font-style: normal\">(</span>" },
    { "[)]", "<span style=\"font-style: normal\">)</span>" },
    { "pv", "<span style=\"font-style: normal\">pv</span>" },
    { "pathovar", "<span style=\"font-style: normal\">pathovar</span>" },
    { "morphovar", "<span style=\"font-style: normal\">morphovar</span>" },
    { "phagovar", "<span style=\"font-style: normal\">phagovar</span>" },
    { "serovar", "<span style=\"font-style: normal\">serovar</span>" },
    { "chemovar", "<span style=\"font-style: normal\">chemovar</span>" },
    { "cultivar", "<span style=\"font-style: normal\">cultivar</span>" },
    { "chemoform", "<span style=\"font-style: normal\">chemoform</span>" },
    { "chemotype", "<span style=\"font-style: normal\">chemotype</span>" },
    { "morphotype", "<span style=\"font-style: normal\">morphotype</span>" },
    { "pathotype", "<span style=\"font-style: normal\">pathotype</span>" },
    { "phagotype", "<span style=\"font-style: normal\">phagotype</span>" },
    { "lysotype", "<span style=\"font-style: normal\">lysotype</span>" },
    { "phase", "<span style=\"font-style: normal\">phase</span>" },
    { "serotype", "<span style=\"font-style: normal\">serotype</span>" },
    { "state", "<span style=\"font-style: normal\">state</span>" },
    { "forma specialis", "<span style=\"font-style: normal\">forma specialis</span>" },
    { "f[.]sp[.]", "<span style=\"font-style: normal\">f.sp.</span>" }

}

--[[
  Liste d'exclusion de noms de clades qui sont français et donc ne doivent pas être en italique
--]]
p.exclude_clades = {
    "Angiospermes"
}

--[[
  Retourne vrai si le nom passé est un nom de clade en français (ça *doit* être un rang clade)
--]]
function p.clade_francais(nom)
    local tst -- on regarde si présence d'accents
    tst = mw.ustring.find(nom, "[éèêëàäâçùüüïîôö]")
    if (tst ~= nil) then
        return true -- visiblement en français on laisse sans mettre en italique
    end
    -- liste d'exclusion de noms traités comme français
    for i = 1, #p.exclude_clades do
        if (p.exclude_clades[i] == nom) then
            -- exception, en français, on laisse sans italiques
            return true
        end
    end
    return false
end

-- si 'true' indique regne tout en italique
p.regnes = {
 ["test"]=false, ["algue"]=true, ["animal"]=false, ["archaea"]=true,
 ["bactérie"]=true, ["champignon"]=true, ["protiste"]=false, ["végétal"]=true, ["virus"]=true,
 ["neutre"]=true, ["eucaryote"]=false, ["procaryote"]=true
}
-- si true indique rang inférieur (ou égal) au genre
p.rangs = {
 ["clade"]=false, ["type"]=false, ["groupe"]=false, ["non classé"]=false, ["non-classé"]=false, ["sous-forme"]=true,
 ["forme"]=true, ["cultivar"]=true, ["variété"]=true, ["sous-espèce"]=true, ["hybride"]=true,
 ["espèce"]=true, ["sous-série"]=true, ["série"]=true, ["sous-section"]=false, ["section"]=false,
 ["sous-genre"]=true, ["genre"]=true, ["sous-tribu"]=false, ["tribu"]=false, ["super-tribu"]=false,
 ["infra-tribu"]=false, ["sous-famille"]=false, ["famille"]=false, ["épifamille"]=false, ["super-famille"]=false,
 ["micro-ordre"]=false, ["infra-ordre"]=false, ["sous-ordre"]=false, ["ordre"]=false, ["super-ordre"]=false,
 ["sous-cohorte"]=false, ["cohorte"]=false, ["super-cohorte"]=false, ["infra-classe"]=false, ["sous-classe"]=false,
 ["classe"]=false, ["super-classe"]=false, ["infra-embranchement"]=false, ["sous-embranchement"]=false, ["embranchement"]=false,
 ["super-embranchement"]=false, ["sous-division"]=false, ["division"]=false, ["super-division"]=false, ["infra-règne"]=false,
 ["rameau"]=false, ["sous-règne"]=false, ["règne"]=false, ["super-règne"]=false, ["sous-domaine"]=false,
 ["domaine"]=false, ["empire"]=false
}
-- retourne true si rang+regne a besoin de l'italique
function p.rang_regne_it(rang, regne)
    if (rang == nil or rang == "" or regne == nil or regne == "") then
        return nil
    end
    local reg = p.regnes[regne]
    if (reg == nil) then
        return nil
    end
    if (reg == true) then
        return true -- tout en italique
    end
    local rag = p.rangs[rang]
    if (rag == nil) then
        return nil
    end
    if (rag == true) then
        return true
    else
        return false
    end
end

-- met un nom scientifique en italique, en respectant les conventions.
-- cette fonction met en italique sans condition.
-- cette fonction présume que le nom passé est *uniquement* un nom scientifique (pas de partie homonyme)
-- la partie rang est utilisée pour détecter les "clades" en français
function p.italique_biologique(nom, rang, regne)
    if (nom == nil or nom == "") then
        return ""
    end
    
    -- si pas besoin de l'italique on laisse
    local it = p.rang_regne_it(rang, regne)
    if (it == nil or it == false) then
        return '<span style="font-style: normal">' .. nom .. '</span>'
    end
    
    -- si rang=clade et qu'on détecte que c'est du français on laisse sans modifier
    if (rang == "clade") then
        if (p.clade_francais(nom)) then
            return '<span style="font-style: normal">' .. nom .. '</span>'
        end
    end
    
    -- on remplace dans le nom toutes les occurrences à protéger
    for i = 1, #p.exclude do
        nom = mw.ustring.gsub(nom, p.exclude[i][1], p.exclude[i][2])
    end
    
    -- on retourne la partie traitée
    -- en insérant les italiques au début et à la fin
    -- attention : si on a traité un élément au tout début (ou fin) il faut le virer et ne
    -- pas remettre de '' au début (ou fin)
    local deb = "''"
    local fin = "''"
    if (mw.ustring.find(nom, "^''")) then
        nom = mw.ustring.sub(nom, 3) -- on supprime les 2 1er
        deb = "" -- pas au début
    end
    if (mw.ustring.find(nom, "''$")) then
        nom = mw.ustring.sub(nom, 1, -3) -- on supprime les 2 derniers
        fin = "" -- pas à la fin
    end
    
    return deb .. nom .. fin
end


-- traite un nom scientifique pour la mise en italique
function p.ns(frame)
    -- on récupère le rang (si cultivar, fonction dédiée)
    local rang = mw.ustring.lower(mw.text.trim(frame.args["rang"] or ""))
    -- on récupère le règne
    local regne = mw.ustring.lower(mw.text.trim(frame.args["règne"] or ""))
    -- juste un wrapper
    if (rang == "cultivar") then
        return ( p.italique_cultivar(p.trim(frame.args[1] or frame:getParent().args[1] or "")) )
    else
        return ( p.italique_biologique(p.trim(frame.args[1] or frame:getParent().args[1] or ""), rang, regne) )
    end
end


-- traite la mise en italiques d'un nom de cultivar. La forme est "XXXXX 'YYY'" (apostrophe simple ou typographique)
-- l'italique n'est que sur la première partie. Retourne nil si cette forme n'est pas détectée
function p.italique_cultivar(nom)
    if (nom == nil or nom == "" or type(nom) ~= "string") then
        return ""
    end

    -- on verifie que le nom se termine par ' ou ’
    local der = mw.ustring.sub(nom, -1)
    if (der ~= "'" and der ~= "’") then
        return nom -- pas bon
    end
    -- on cherche la partie YYY
    local pd1, pf1 = mw.ustring.find(nom, "['].*[']$")
    local pd2, pf2 = mw.ustring.find(nom, "[‘].*[’]$")
    if (pd1 == nil and pd2 == nil) then
        return nom -- pas trouvé
    end
    local debut = pd1 or pd2
    local fin = pf1 or pf2
    
    -- on récupère le début (à mettre en italiques)
    local part1 = mw.ustring.sub(nom, 1, debut-1)
    if (part1 == nil or part1 == "") then
        return nom
    end
    local itpart1 = p.italique_biologique(part1, "espès", "animal")
    local reste = mw.ustring.sub(nom, debut)
    return itpart1 .. reste
end

-- traite un nom de cultivar pour la mise en italique
function p.nc(frame)
    -- juste un wrapper
    return ( p.italique_cultivar(p.trim(frame.args[1] or frame:getParent().args[1] or "")) )
end



-- applique la forme italique pour le titre de l'article (DISPLAYTITLE) à partir du
-- nom scientifique reçu en paramètre. Gère la partie homonymie. Détecte un NV
function p.titre(frame)
    local ttr
    local cat = ""

    -- le nom scientifique
    local ns = p.trim(frame.args[1] or frame:getParent().args[1] or "")
    if (ns == nil or ns == "") then
        -- pas de nom scientifique, on ne peut pas travailler
        return ""
    end
    
    -- on récupère règne et rang si présents
    local regne = frame.args["règne"] or frame:getParent().args["règne"]
    local rang = frame.args["rang"] or frame:getParent().args["rang"]
    regne = mw.text.trim(regne or "")
    rang = mw.text.trim(rang or "")

    -- test temporaire : si le nom scientifique contient de la mise en forme
    -- on range l'article dans une catégorie pour les détecter
    --- selon les combinaisons règne+rang on fait des choses différentes
    local a_tester = "[[{'†éèêëàâäùüûçîïôö]"
    if (regne == "virus") then
        a_tester = nil -- on trouve de tout dans les virus
    end
    if (rang == "clade") then
        a_tester = "[[{'†]" -- pour les clades les noms peuvent être en français
    end
    if (regne == "animal" and rang == "hybride") then
        a_tester = "[[{'†]" -- pour les hybrides animaux les noms peuvent être en français
    end
    if (rang == "cultivar") then
        a_tester = "[[{†]" -- les cultivars contiennent des ' ou ‘’
    end
    
    -- seulement si on a un test à faire
    if (a_tester ~= nil) then
        local tst = mw.ustring.find(ns, a_tester)
        if (tst) then
            cat = "{{Atik Biyoloji pou korije|clef=NS|"
                 .. "doc=Modèl:Taxobox taxon|message=Nom de taxon '"
                 .. mw.text.nowiki(ns) .. "' non reconnu}}"
        end
    end

    -- spécial : si paramètre "titre" → on utilise à la place
    local ft = frame.args["titre"] or frame:getParent().args["titre"]
    if (ft) then
        -- titre forcé : on l'utilise à la place du titre réel
        -- et on ne vérifie pas le namespace
        ttr = ft
    else
        -- le titre
        local titre = mw.title.getCurrentTitle()
        if (titre.namespace ~= 0) then
            -- seulement les articles !
            return ""
        end
        ttr = titre.text
    end
    
    if (ttr == ns) then
        -- titre exactement NS → direct
        if (ft) then
            if (rang == "cultivar") then
                return frame:preprocess("<nowiki>" .. cat .. "{{DISPLAYTITLE:" .. p.italique_cultivar(ns) .. "|noerror}}</nowiki>")
            else
                return frame:preprocess("<nowiki>" .. cat .. "{{DISPLAYTITLE:" .. p.italique_biologique(ns, rang, regne) .. "|noerror}}</nowiki>")
            end
        else
            if (rang == "cultivar") then
                return frame:preprocess(cat .. "{{DISPLAYTITLE:" .. p.italique_cultivar(ns) .. "|noerror}}")
            else
                return frame:preprocess(cat .. "{{DISPLAYTITLE:" .. p.italique_biologique(ns, rang, regne) .. "|noerror}}")
            end
        end
    end
    
    -- si le titre est plus court que le NS ça ne peut être NS+homonymie
    local lng = mw.ustring.len(ns)
    if (mw.ustring.len(ttr) <= lng) then
    	if (cat == "") then
    		return ""
    	else
    		if (ft) then
            	return frame:preprocess("<nowiki>" .. cat .. "</nowiki>")
        	else
            	return frame:preprocess(cat) -- on ne fait rien
        	end
        end
    end
    
    -- on récupère les 'lng' premiers caractères du titre : ça doit être égal au NS
    -- sinon ça veut dire que ce n'est pas NS+homonymie
    local p1 = mw.ustring.sub(ttr, 1, lng)
    if (p1 ~= ns) then
    	if (cat ~= "") then
        	return frame:preprocess(cat) -- on ne fait rien
    	else
    		return ""
		end
    end
    
    -- la partie homonymie seule
    local hom = mw.ustring.sub(ttr, lng+1)
    
    -- on valide que la partie homonymie contient des ()
    local tst = mw.ustring.find(ttr, "[(]")
    if (tst == nil) then
    	if (cat == "") then
    		return ""
    	else
    		return frame:preprocess(cat) -- on ne touche rien
    	end
    end

    -- on retourne la mise en forme du NS italique + la partie homonymie
    if (ft) then
        if (rang == "cultivar") then
            return frame:preprocess("<nowiki>" .. cat .. "{{DISPLAYTITLE:" .. p.italique_cultivar(ns) .. hom .. "|noerror}}</nowiki>")
        else
            return frame:preprocess("<nowiki>" .. cat .. "{{DISPLAYTITLE:" .. p.italique_biologique(ns, rang, regne) .. hom .. "|noerror}}</nowiki>")
        end
    else
        if (rang == "cultivar") then
            return frame:preprocess(cat .. "{{DISPLAYTITLE:" .. p.italique_cultivar(ns) .. hom .. "|noerror}}")
        else
            return frame:preprocess(cat .. "{{DISPLAYTITLE:" .. p.italique_biologique(ns, rang, regne) .. hom .. "|noerror}}")
        end
    end
end


-- met un nom scientifique en italique, en respectant les conventions. Utilisable uniquement :
--  - dans le modèle {{taxobox}} car il utilise une syntaxe HTML et non wiki pour tenir compte du style CSS associé
--  - sur des taxons qui sont à coup sur en italiques (inf. au genre) car ne sait pas quelles sont les conditions autour
--  - ne gère pas la partie homonymie (pas supposé se rencontrer dans les noms de taxon)
function p.italique_taxon(nom, rang)
    if (nom == nil or nom == "") then
        return ""
    end
    
    -- si c'est un clade et détecté français on enlève l'italique
    if (rang == "clade") then
        if (p.clade_francais(nom)) then
            return '<span style="font-style: normal">' .. nom .. '</span>'
        end
    end
    
    -- on remplace dans le nom toutes les occurrences à protéger
    for i = 1, #p.exclude_span do
        nom = mw.ustring.gsub(nom, p.exclude_span[i][1], p.exclude_span[i][2])
    end
    
    return nom
end

-- wrapper
function p.nt(frame)
    local nom = mw.text.trim(frame.args[1] or frame:getParent().args[1] or "")
    if (nom == "") then
        return ""
    end
    local nom2 = mw.text.trim(frame.args[2] or frame:getParent().args[2] or "")
    local rang = mw.text.trim(frame.args[3] or frame:getParent().args[3] or "")
    
    local resu
    if (nom2 == "") then
        resu = p.italique_taxon(nom, rang)
    else
        resu = p.italique_taxon(nom2, rang)
    end
    
    if (nom == resu) then
        return " [[" .. resu .. "]]"
    else
        return frame:preprocess(" [[" .. nom .. "|" .. resu .. "]]")
    end
end



-- module
return p