Difference between revisions of "Module:TaxonItalics"

From blackwiki
Jump to navigation Jump to search
blackwiki>Frietjes
(hybridDeitalicized never used and causing error in Grapefruit)
m (51 revisions imported)
 
(17 intermediate revisions by 4 users not shown)
Line 10: Line 10:
 
   * Else if the name is made up of three words and the second word is a
 
   * Else if the name is made up of three words and the second word is a
 
     botanical connecting term or a variant of "cf.", de-italicize the
 
     botanical connecting term or a variant of "cf.", de-italicize the
     connecting term and add italic markup to the outside of the name.  
+
     connecting term and add italic markup to the outside of the name.
 
   * Else just add italic markup to the outside of the name.
 
   * Else just add italic markup to the outside of the name.
 +
The module also:
 +
* Ensures that the hybrid symbol, ×, and parentheses are not italicized
 +
* Has an option to abbreviate all parts of taxon names other than the last
 +
  to the first letter (e.g. "Pinus sylvestris var. sylvestris" becomes
 +
  "P. s. var. sylvestris").
 +
* Has an option to wikilink the italicized name to the input name.
 
=============================================================================]]
 
=============================================================================]]
  
 
local p = {}
 
local p = {}
 +
local l = {} -- used to store purely local functions
  
 +
--connecting terms in three part names (e.g. Pinus sylvestris var. sylvestris)
 
local cTerms3 = {
 
local cTerms3 = {
subspecies = "subsp.",
+
--subsp.
["subsp."] = "subsp.",
+
    subspecies = "subsp.",
subsp = "subsp.",
+
    ["subsp."] = "subsp.",
["ssp."] = "subsp.",
+
    subsp = "subsp.",
ssp = "subsp.",
+
    ["ssp."] = "subsp.",
varietas = "var.",
+
    ssp = "subsp.",
["var."] = "var.",
+
    --var.
var = "var.",
+
    varietas = "var.",
subvarietas = "subvar.",
+
    ["var."] = "var.",
["subvar."] = "subvar.",
+
    var = "var.",
subvar = "subvar.",
+
    --subvar.
forma = "f.",
+
    subvarietas = "subvar.",
["f."] = "f.",
+
    ["subvar."] = "subvar.",
f = "f.",
+
    subvar = "subvar.",
subforma = "subf.",
+
    --f.
["subf."] = "subf.",
+
    forma = "f.",
subf = "subf."
+
    ["f."] = "f.",
}
+
    f = "f.",
 +
    --subf.
 +
    subforma = "subf.",
 +
    ["subf."] = "subf.",
 +
    subf = "subf."
 +
    }
 +
--connecting terms in two part names (e.g. Pinus sect. Pinus)
 
local cTerms2 = {
 
local cTerms2 = {
subgenus = "subg.",
+
--subg.
["subg."] = "subg.",
+
    subgenus = "subg.",
subg = "subg.",
+
    ["subgen."] = "subg.",
section = "sect.",
+
    ["subg."] = "subg.",
["sect."] = "sect.",
+
    subg = "subg.",
subsection = "subsect.",
+
    --supersect.
subsect = "subsect.",
+
    supersection = "supersect.",
["subsect."] = "subsect.",
+
    ["supersect."] = "supersect.",
series = "ser.",
+
    supersect = "supersect.",
ser = "ser.",
+
    --sect.
["ser."] = "ser.",
+
    section = "sect.",
subseries = "subser.",
+
    ["sect."] = "sect.",
subser = "subser.",
+
    sect = "sect.",
["subser."] = "subser.",
+
    --subsect.
["cf."] = "cf.",
+
    subsection = "subsect.",
cf = "cf.",
+
    ["subsect."] = "subsect.",
["c.f."] = "cf."
+
    subsect = "subsect.",
}
+
    --ser.
 +
    series = "ser.",
 +
    ["ser."] = "ser.",
 +
    ser = "ser.",
 +
    --subser.
 +
    subseries = "subser.",
 +
    ["subser."] = "subser.",
 +
    subser = "subser.",
 +
    --cf.
 +
    cf = "cf.",
 +
    ["cf."] = "cf.",
 +
    ["c.f."] = "cf."
 +
    }
  
 
--[[=========================================================================
 
--[[=========================================================================
Italicize a taxon name appropriately.
+
Main function to italicize a taxon name appropriately.
 
=============================================================================]]
 
=============================================================================]]
 
function p.main(frame)
 
function p.main(frame)
local name = frame.args[1] or ''
+
    local name = frame.args[1] or ''
local linked = frame.args['linked'] == 'yes'
+
    local linked = frame.args['linked'] == 'yes'
return p.italicizeTaxonName(name, linked)
+
    local abbreviated = frame.args['abbreviated'] == 'yes'
 +
    return p.italicizeTaxonName(name, linked, abbreviated)
 
end
 
end
  
function p.italicizeTaxonName(name, linked)
+
--[[=========================================================================
local italMarker = "''"
+
Utility local function to abbreviate an input string to its first character
local hybridSymbol = "×"
+
followed by ".".
-- trim the name and replace any use of the HTML italic tags by Wikimedia markup
+
Both "×" and an HTML entity at the start of the string are skipped over in
name = string.gsub(mw.text.trim(name), "</?i>", italMarker)
+
determining first character, as is an opening parenthesis and an opening ",
local result = name
+
which cause a matching closing character to be included.
if name ~= '' then
+
=============================================================================]]
if string.sub(name, 1, 2) == "''" or string.sub(name, -2) == "''" then
+
function l.abbreviate(str)
-- do nothing if the name already has italic markers at the start or end
+
local result = ""
else
+
local hasParentheses = false
name = string.gsub(name, "''", "") -- first remove internal italics
+
local isQuoted = false
local words = mw.text.split(name, " ", true)
+
if mw.ustring.len(str) < 2 then
if words[2] == hybridSymbol then
+
--single character strings are left unchanged
words[1] = words[1] .. italMarker .. " " .. hybridSymbol
+
result = str
words[3] = " " .. italMarker .. words[3]
+
else
table.remove(words, 2)
+
--skip over an opening parenthesis that could be present at the start of the string
-- hybridDeitalicized = true
+
if mw.ustring.sub(str,1,1) == "(" then
end
+
hasParentheses = true
local deitalicized = false
+
result = "("
if #words == 4 then
+
str = mw.ustring.sub(str,2,mw.ustring.len(str))
-- test for the third word of a four word name being a connecting term
+
elseif mw.ustring.sub(str,1,1) == '"' then
if cTerms3[words[3]] then
+
isQuoted = true
-- de-italicize the connecting term by adding internal italic markup
+
result = '"'
result = words[1] .. " " .. words[2] .. italMarker .. " " .. cTerms3[words[3]] .. " " .. italMarker .. words[4]
+
str = mw.ustring.sub(str,2,mw.ustring.len(str))
deitalicized = true
+
end
end
+
--skip over a hybrid symbol that could be present at the start of the string
elseif #words == 3 then
+
if mw.ustring.sub(str,1,1) == "×" then
-- test for the second word of a three word name being a connecting term
+
result = "×"  
if cTerms2[words[2]] then
+
str = mw.ustring.sub(str,2,mw.ustring.len(str))
-- de-italicize the connecting term by adding internal italic markup
+
end
result = words[1] .. italMarker .. " " .. cTerms2[words[2]] .. " " .. italMarker .. words[3]
+
--skip over an HTML entity that could be present at the start of the string
deitalicized = true
+
if mw.ustring.sub(str,1,1) == "&" then
end
+
local i,dummy = mw.ustring.find(str,";",2,plain)
else
+
result = result .. mw.ustring.sub(str,1,i)
-- do nothing except un-italicize hybrid symbol
+
str = mw.ustring.sub(str,i+1,mw.ustring.len(str))
result = name:gsub(" " .. hybridSymbol .. " ", "''%0''")
+
end
end
+
--if there's anything left, reduce it to its first character plus ".",
-- add outside markup
+
--adding the closing parenthesis or quote if required
if linked then
+
if str ~= "" then  
if deitalicized then
+
result = result .. mw.ustring.sub(str,1,1) .. "."
result = "[[" .. name .. "|" .. italMarker .. result .. italMarker .. "]]"
+
if hasParentheses then result = result .. ")"
else
+
elseif isQuoted then result = result .. '"'
result = italMarker .. "[[" .. name .. "]]" .. italMarker
 
end
 
else
 
result = italMarker .. result .. italMarker
 
 
end
 
end
 
end
 
end
 
end
 
end
 
return result
 
return result
 +
end
 +
 +
--[[=========================================================================
 +
The function which does the italicization.
 +
=============================================================================]]
 +
function p.italicizeTaxonName(name, linked, abbreviated)
 +
    local italMarker = "''"
 +
    -- begin by tidying the input name: trim; replace any use of the HTML
 +
    -- italic tags by Wikimedia markup; replace any alternatives to the hybrid
 +
    -- symbol by the symbol itself; prevent the hybrid symbol being treated as
 +
    -- a 'word' by converting a following space to the HTML entity
 +
    name = string.gsub(mw.text.trim(name), "</?i>", italMarker)
 +
    name = string.gsub(string.gsub(name, "&#215;", "×"), "&times;", "×")
 +
    name = string.gsub(name, "</?span.->", "") -- remove any span markup
 +
    name = string.gsub(name, "× ", "×&#32;")
 +
    -- now italicize and abbreviate if required
 +
    local result = name
 +
    if name ~= '' then
 +
        if string.sub(name,1,2) == "''" or string.sub(name,-2) == "''" then
 +
            -- do nothing if the name already has italic markers at the start or end
 +
        else
 +
            name = string.gsub(name, "''", "") -- first remove any internal italics
 +
            local words = mw.text.split(name, " ", true)
 +
            if #words == 4 and cTerms3[words[3]] then
 +
                -- the third word of a four word name is a connecting term
 +
                -- ensure the connecting term isn't italicized
 +
                words[3] = '<span style="font-style:normal;">' .. cTerms3[words[3]] .. '</span>'
 +
                if abbreviated then
 +
                words[1] = l.abbreviate(words[1])
 +
                    words[2] = l.abbreviate(words[2])
 +
            end
 +
                result = words[1] .. " " .. words[2] .. " " .. words[3] .. " " .. words[4]
 +
            elseif #words == 3 and cTerms2[words[2]] then
 +
                -- the second word of a three word name is a connecting term
 +
                -- ensure the connecting term isn't italicized
 +
                words[2] = '<span style="font-style:normal;">' .. cTerms2[words[2]] .. '</span>'
 +
                if abbreviated then
 +
                words[1] = l.abbreviate(words[1])
 +
                end
 +
                result = words[1] .. " " .. words[2] .. " " .. words[3]
 +
            else
 +
                -- not a name as above; only deal with abbreviation
 +
                if abbreviated then
 +
                if #words > 1 then
 +
                result = l.abbreviate(words[1])
 +
                for i = 2, #words-1, 1 do
 +
                result = result .. " " .. l.abbreviate(words[i])
 +
                end
 +
                result = result .. " " .. words[#words]
 +
                end
 +
                else
 +
                result = name
 +
                end
 +
            end
 +
            -- deal with any hybrid symbol as it should not be italicized
 +
            result = string.gsub(result, "×", '<span style="font-style:normal;">×</span>')
 +
            -- deal with any parentheses as they should not be italicized
 +
            result = string.gsub(string.gsub(result,"%(",'<span style="font-style:normal;">(</span>'),"%)",'<span style="font-style:normal;">)</span>')
 +
            -- any question marks surrounded by spans can have the spans joined
 +
            result = string.gsub(result,'</span>%?<span style="font%-style:normal;">','?')
 +
        -- add outside markup
 +
            if linked then
 +
                if result ~= name then
 +
                    result = "[[" .. name .. "|" .. italMarker .. result .. italMarker .. "]]"
 +
                else
 +
                    result = italMarker .. "[[" .. name .. "]]" .. italMarker
 +
                end
 +
            else
 +
                result = italMarker .. result .. italMarker
 +
            end
 +
        end
 +
    end
 +
    return result
 
end
 
end
  
 
return p
 
return p

Latest revision as of 16:54, 29 September 2020

Module:TaxonItalics Template:Toolbar

Purpose

The module supports the correct italicization of scientific names. Botanical (ICNafp) names may contain "connecting terms"; these must not be italicized. The hybrid symbol, ×, should also not be italicized. The module optionally wikilinks and abbreviates italicized names.

For non-virus taxa, italics are used at the rank of genus or below. The module does not decide whether a scientific name should be italicized. Use {{Is italic taxon}} for this purpose.

Usage

  • {{#invoke:TaxonItalics|main|TAXON_NAME}} – italicizes a taxon name
  • {{#invoke:TaxonItalics|main|TAXON_NAME|linked=yes}} – italicizes a taxon name, wikilinking the italicized output to the unchanged input
  • {{#invoke:TaxonItalics|main|TAXON_NAME|abbreviated=yes}} – italicizes a taxon name, abbreviating all but the last part to the first letter

It can also be used via {{Taxon italics}}.

Examples

Just italicized

Connecting terms
  • Pinus subg. Pinus → Pinus subg. Pinus
  • P. subgenus Pinus → P. subg. Pinus
  • P. subsect. Pinaster → P. subsect. Pinaster
  • Acer tataricum subsp. ginnala → Acer tataricum subsp. ginnala
  • Aster ericoides var. ericoides → Aster ericoides var. ericoides
  • A. ericoides varietas ericoides → A. ericoides var. ericoides
  • A. e. subvar. ericoides → A. e. subvar. ericoides

Botanical names may contain only one infraspecific epithet; a string like "Fragaria vesca subsp. vesca f. semperflorens" is a classification, not a name, and is not handled by the module.

Hybrid symbols
  • Elaeagnus × submacrophylla → Elaeagnus × submacrophylla
  • ×Beallara → ×Beallara
  • &times; Beallara → × Beallara
  • {{hybrid}}Beallara → ×Beallara

Linked

Using |linked=yes

Abbreviated

Using |abbreviated=yes

  • Populus sect. Aigeiros → P. sect. Aigeiros
  • Acer tataricum subsp. ginnala → A. t. subsp. ginnala
  • [also linked] × Sorbaronia mitschurinii → × S. mitschurinii
  • [also linked] Elaeagnus × submacrophylla → E. × submacrophylla
  • Elaeagnus ×submacrophylla → E. ×submacrophylla
  • Elaeagnus {{hybrid}} submacrophylla → E. × submacrophylla

For even more examples, see the testcases.



--[[=========================================================================
Italicize a taxon name appropriately by invoking italicizeTaxonName.
The algorithm used is:
* If the name has italic markup at the start or the end, do nothing.
* Else
  * Remove (internal) italic markup.
  * If the name is made up of four words and the third word is a
    botanical connecting term, de-italicize the connecting term and add italic
    markup to the outside of the name.
  * Else if the name is made up of three words and the second word is a
    botanical connecting term or a variant of "cf.", de-italicize the
    connecting term and add italic markup to the outside of the name.
  * Else just add italic markup to the outside of the name.
 The module also:
 * Ensures that the hybrid symbol, ×, and parentheses are not italicized
 * Has an option to abbreviate all parts of taxon names other than the last
   to the first letter (e.g. "Pinus sylvestris var. sylvestris" becomes
   "P. s. var. sylvestris").
 * Has an option to wikilink the italicized name to the input name.
=============================================================================]]

local p = {}
local l = {} -- used to store purely local functions

--connecting terms in three part names (e.g. Pinus sylvestris var. sylvestris)
local cTerms3 = {
	--subsp.
    subspecies = "subsp.",
    ["subsp."] = "subsp.",
    subsp = "subsp.",
    ["ssp."] = "subsp.",
    ssp = "subsp.",
    --var.
    varietas = "var.",
    ["var."] = "var.",
    var = "var.",
    --subvar.
    subvarietas = "subvar.",
    ["subvar."] = "subvar.",
    subvar = "subvar.",
    --f.
    forma = "f.",
    ["f."] = "f.",
    f = "f.",
    --subf.
    subforma = "subf.",
    ["subf."] = "subf.",
    subf = "subf."
    }
--connecting terms in two part names (e.g. Pinus sect. Pinus)
local cTerms2 = {
	--subg.
    subgenus = "subg.",
    ["subgen."] = "subg.",
    ["subg."] = "subg.",
    subg = "subg.",
    --supersect.
    supersection = "supersect.",
    ["supersect."] = "supersect.",
    supersect = "supersect.",
    --sect.
    section = "sect.",
    ["sect."] = "sect.",
    sect = "sect.",
    --subsect.
    subsection = "subsect.",
    ["subsect."] = "subsect.",
    subsect = "subsect.",
    --ser.
    series = "ser.",
    ["ser."] = "ser.",
    ser = "ser.",
    --subser.
    subseries = "subser.",
    ["subser."] = "subser.",
    subser = "subser.",
    --cf.
    cf = "cf.",
    ["cf."] = "cf.",
    ["c.f."] = "cf."
    }

--[[=========================================================================
Main function to italicize a taxon name appropriately.
=============================================================================]]
function p.main(frame)
    local name = frame.args[1] or ''
    local linked = frame.args['linked'] == 'yes'
    local abbreviated = frame.args['abbreviated'] == 'yes'
    return p.italicizeTaxonName(name, linked, abbreviated)
end

--[[=========================================================================
Utility local function to abbreviate an input string to its first character
followed by ".".
Both "×" and an HTML entity at the start of the string are skipped over in
determining first character, as is an opening parenthesis and an opening ",
which cause a matching closing character to be included.
=============================================================================]]
function l.abbreviate(str)
	local result = ""
	local hasParentheses = false
	local isQuoted = false
	if mw.ustring.len(str) < 2 then
		--single character strings are left unchanged
		result = str
	else
		--skip over an opening parenthesis that could be present at the start of the string
		if mw.ustring.sub(str,1,1) == "(" then
			hasParentheses = true
			result = "(" 
			str = mw.ustring.sub(str,2,mw.ustring.len(str))
		elseif mw.ustring.sub(str,1,1) == '"' then
			isQuoted = true
			result = '"'
			str = mw.ustring.sub(str,2,mw.ustring.len(str))
		end
		--skip over a hybrid symbol that could be present at the start of the string
		if mw.ustring.sub(str,1,1) == "×" then
			result = "×" 
			str = mw.ustring.sub(str,2,mw.ustring.len(str))
		end
		--skip over an HTML entity that could be present at the start of the string
		if mw.ustring.sub(str,1,1) == "&" then
			local i,dummy = mw.ustring.find(str,";",2,plain)
			result = result .. mw.ustring.sub(str,1,i)
			str = mw.ustring.sub(str,i+1,mw.ustring.len(str))
		end
		--if there's anything left, reduce it to its first character plus ".",
		--adding the closing parenthesis or quote if required
		if str ~= "" then 
			result = result .. mw.ustring.sub(str,1,1) .. "."
			if hasParentheses then result = result .. ")"
			elseif isQuoted then result = result .. '"'
			end
		end
	end
	return result
end

--[[=========================================================================
The function which does the italicization.
=============================================================================]]
function p.italicizeTaxonName(name, linked, abbreviated)
    local italMarker = "''"
    -- begin by tidying the input name: trim; replace any use of the HTML
    -- italic tags by Wikimedia markup; replace any alternatives to the hybrid
    -- symbol by the symbol itself; prevent the hybrid symbol being treated as
    -- a 'word' by converting a following space to the HTML entity
    name = string.gsub(mw.text.trim(name), "</?i>", italMarker)
    name = string.gsub(string.gsub(name, "&#215;", "×"), "&times;", "×")
    name = string.gsub(name, "</?span.->", "") -- remove any span markup
    name = string.gsub(name, "× ", "×&#32;")
    -- now italicize and abbreviate if required
    local result = name
    if name ~= '' then
        if string.sub(name,1,2) == "''" or string.sub(name,-2) == "''" then
            -- do nothing if the name already has italic markers at the start or end
        else
            name = string.gsub(name, "''", "") -- first remove any internal italics
            local words = mw.text.split(name, " ", true)
            if #words == 4 and cTerms3[words[3]] then
                -- the third word of a four word name is a connecting term
                -- ensure the connecting term isn't italicized
                words[3] = '<span style="font-style:normal;">' .. cTerms3[words[3]] .. '</span>'
                if abbreviated then
                	words[1] = l.abbreviate(words[1])
                    words[2] = l.abbreviate(words[2])
            	end
                result = words[1] .. " " .. words[2] .. " " .. words[3] .. " " .. words[4]
            elseif #words == 3 and cTerms2[words[2]] then
                -- the second word of a three word name is a connecting term
                -- ensure the connecting term isn't italicized
                words[2] = '<span style="font-style:normal;">' .. cTerms2[words[2]] .. '</span>'
                if abbreviated then
                	words[1] = l.abbreviate(words[1])
                end
                result = words[1] .. " " .. words[2] .. " " .. words[3]
            else
                -- not a name as above; only deal with abbreviation
                if abbreviated then
                	if #words > 1 then
                		result = l.abbreviate(words[1])
                		for i = 2, #words-1, 1 do
                			result = result .. " " .. l.abbreviate(words[i])
                		end
                		result = result .. " " .. words[#words]
                	end
                else
                	result = name
                end
            end
            -- deal with any hybrid symbol as it should not be italicized
            result = string.gsub(result, "×", '<span style="font-style:normal;">×</span>')
             -- deal with any parentheses as they should not be italicized
            result = string.gsub(string.gsub(result,"%(",'<span style="font-style:normal;">(</span>'),"%)",'<span style="font-style:normal;">)</span>')
            -- any question marks surrounded by spans can have the spans joined
            result = string.gsub(result,'</span>%?<span style="font%-style:normal;">','?')
        	-- add outside markup
            if linked then
                if result ~= name then
                    result = "[[" .. name .. "|" .. italMarker .. result .. italMarker .. "]]"
                else
                    result = italMarker .. "[[" .. name .. "]]" .. italMarker
                end
            else
                result = italMarker .. result .. italMarker
            end
        end
    end
    return result
end

return p