Loading
  • 21 Aug, 2019

  • By, Wikipedia

Module:GHS Phrases

As of 31 May 2023:

  • GHS H-phrases (112) H200, H201, H202, H203, H204, H205, H206, H207, H208, H209, H210, H211, H220, H221, H222, H223, H224, H225, H226, H227, H228, H229, H230, H231, H232, H240, H241, H242, H250, H251, H252, H260, H261, H270, H271, H272, H280, H281, H282, H283, H284, H290, H300, H300+H310, H300+H310+H330, H300+H330, H301, H301+H311, H301+H311+H331, H301+H331, H302, H302+H312, H302+H312+H332, H302+H332, H303, H303+H313, H303+H313+H333, H303+H333, H304, H305, H310, H310+H330, H311, H311+H331, H312, H312+H332, H313, H313+H333, H314, H315, H315+H320, H316, H317, H318, H319, H320, H330, H331, H332, H333, H334, H335, H336, H340, H341, H350, H350i, H351, H360, H360D, H360Df, H360F, H360FD, H360Fd, H361, H361d, H361f, H361fd, H362, H370, H371, H372, H373, H400, H401, H402, H410, H411, H412, H413, H420, H441
Order entered: |H201|H200| to check sorting.
  • GHS P-phrases (183) P102, P103, P201, P202, P203, P210, P211, P212, P220, P221, P222, P223, P230, P231, P231+P232, P232, P233, P234, P235, P235+P410, P236, P240, P241, P242, P243, P244, P250, P251, P260, P261, P262, P263, P264, P264+P265, P265, P270, P271, P272, P273, P280, P281, P282, P283, P284, P285, P301, P301+P310, P301+P310+P330, P301+P312, P301+P312+P330, P301+P330+P331, P302, P302+P312, P302+P317, P302+P334, P302+P335+P334, P302+P350, P302+P352, P302+P352+P312, P302+P353, P302+P361+P354, P303, P303+P361+P353, P303+P361+P353+P315, P304, P304+P312, P304+P317, P304+P340, P304+P340+P310, P304+P340+P311, P304+P340+P312, P304+P340+P315, P304+P341, P305, P305+P351+P338, P305+P351+P338+P310, P305+P354+P338, P306, P306+P360, P307, P307+P311, P308, P308+P310, P308+P311, P308+P313, P308+P316, P308+P360, P309, P309+P311, P310, P311, P312, P313, P314, P315, P318, P320, P321, P322, P330, P331, P332, P332+P313, P332+P317, P333, P333+P313, P333+P317, P334, P335, P335+P334, P336, P336+P315, P336+P317, P337, P337+P313, P337+P317, P338, P340, P341, P342, P342+P311, P342+P316, P350, P351, P352, P353, P354, P360, P361, P361+P364, P362, P362+P364, P363, P364, P370, P370+P372+P380+P373, P370+P376, P370+P378, P370+P380, P370+P380+P375, P370+P380+P375+P378, P371, P371+P380+P375, P372, P373, P374, P375, P376, P377, P378, P380, P381, P390, P391, P401, P402, P402+P404, P403, P403+P233, P403+P235, P404, P405, P406, P407, P410, P410+P403, P410+P412, P411, P411+P235, P412, P413, P420, P422, P501, P502, P503
Order entered: |P103|P102| to check sorting.

Features

Hide Doubles

Repeated phrase codes are hidden:

  • {{GHS phrases|H400|H401|H401|H401}}H400, H401

Omit Rules

|omit=true (default)
Omit Rules as applied by {{GHS phrases}} ()

Omit Rules: when the keep ID is present, do not show the omit ID phrase
• keep H314, omit H318
• keep P203, omit P103
• keep P413, omit P235
• keep H411, omit H401
• keep P411, omit P235
• keep H412, omit H402
• keep H410, omit H400
• keep P236, omit P234

  • Categorised as Category:GHS warnings (1) under "O"
  • Source: "Globally Harmonized System of Classification and Labelling of Chemicals" (pdf). 2021. Annex 3: Codification of Statements and Pictograms (pp 268–385).
  • {{GHS phrases|H314|H318}}H314

All module functions

module function template note
main {{GHS phrases}}
{{H-phrases}} {{P-phrases}}

|setid=H, P preset
listAll {{GHS phrases/inline}} equals main + |listtype=inline
numberOfPhrases {{GHS phrases/number of phrases}}
listAll {{GHS phrases/list all}}
listOmitRules {{GHS phrases/list omit rules}} documentation only; no |setid=

Tracking

See also

Lists: GHS hazard statements, GHS precautionary statements

  1. ^ "Globally Harmonized System of Classification and Labelling of Chemicals" (pdf). 2021. Annex 3: Codification of Statements and Pictograms (pp 268–385).
--------------------------------------------------------------------------------
-- Module:GHS phrases
-- 
-- main: reads GHS parameters (arguments like "H301", "P401")
--		and returns for each (listtype='abbr'):
--		phraseID visible; formal phrase text as <abbr title="...">
-- setID	= "H" or "P"
-- phraseID = e.g. "H201", "P231+P234"
-- phrase text read from array tables in [[Module:GHS phrases/data]]
--
-- Implements: [[Template:GHS phrases]]
-- Helppage: [[Template:GHS phrases]]
-- Error category: [[Category:GHS errors]], [[Category:GHS warnings]] (mainspace pages only)
--
-- Also: 
-- listAll(), numberOfPhrases(), listOmitRules(),
-- listtype, omit
--------------------------------------------------------------------------------
require('strict')
local r = {}	-- "r" for return, so no confusion with setID P
local GHSdata	= mw.loadData('Module:GHS phrases/data')
local getArgs	= require('Module:Arguments').getArgs
local tTools	= require('Module:TableTools')
local yesno		= require('Module:Yesno')
local tArgName	= {} -- named parameters (setid, omit, listtype)
local tMessagesToShow = {} -- the tail: Preview, Categories

--------------------------------------------------------------------------------
-- wlHelpPage
--
-- Formats page as [[Helppage#Section|Label]]
-- by default, sLabel == sSection
--------------------------------------------------------------------------------
local function wlHelpPage(sSection, sLabel)
local sHelpPage = 'Template:GHS phrases'
	
	if sLabel == nil then sLabel = sSection end
	
	if (sLabel or '') == '' then
		sLabel = ''
	else
		sLabel = '|' .. sLabel 
	end
	if (sSection or '') == '' then
		sSection = ''
	else
		sSection = '#' .. sSection
	end
	return '[[' .. sHelpPage .. sSection .. sLabel .. ']]'
end

--------------------------------------------------------------------------------
-- addErrorCategory
--
-- Formats as [[Category:GHS errors|catsort]]
-- or '' when in other namespace.
-- sCatsort option using: H, P, _
--------------------------------------------------------------------------------
local function addErrorCategory(sCatsort)
local pagetype = require('Module:Pagetype').main
	
	local wlErrCat = ''
	if pagetype() == 'article' then -- mainspace only
		if sCatsort == nil then sCatsort = tArgName['setID'] end
		
		if sCatsort == '' then
			wlErrCat = '[[Category:GHS errors]]'
		else
			wlErrCat = '[[Category:GHS errors|' .. sCatsort .. ']]'
		end
	else
		return ''
	end

	table.insert(tMessagesToShow, wlErrCat)
	return
end

--------------------------------------------------------------------------------
-- addWarningCategory
--
-- Formats as [[Category:GHS warnings|catsort]]
-- mainspace only, or '' when in other namespace.
-- sCatsort option using: H, P, U, ?, D, O
--------------------------------------------------------------------------------
local function addWarningCategory(sCatsort)
local pagetype = require('Module:Pagetype').main
if sCatsort == nil then sCatsort = tArgName['setID'] end
		
	local wlWarnCat = ''
	if pagetype() == 'article' then -- mainspace only
		if sCatsort == '' then
			wlWarnCat = '[[Category:GHS warnings]]'
		else
			wlWarnCat = '[[Category:GHS warnings|' .. sCatsort .. ']]'
		end
	else
		return 
	end

	table.insert(tMessagesToShow, wlWarnCat)
	return
end

--------------------------------------------------------------------------------
-- addPreviewMsg
--------------------------------------------------------------------------------
local function addPreviewMsg(sMsg)
local previewWarn = require('Module:If preview')._warning
	table.insert(tMessagesToShow, previewWarn({sMsg}))
	return
end

--------------------------------------------------------------------------------
-- showPreviewMsg
--
-- show table tMessagesToShow
-- preview-messages and errorcat
-- all namespaces
--------------------------------------------------------------------------------
local function showPreviewMsg()
	if tTools.size(tMessagesToShow) > 0 then
		return table.concat(tMessagesToShow, '')
	else
		return ''
	end
end

--------------------------------------------------------------------------------
-- applyRemoveDuplicates
--
-- returns edited table, with double Codes removed
-- adds warning with codes.
-- base table tArgs is walked through by a iwalker that reads a singel code,
-- then a ikiller checks the upward part of the same table to delete all copies
-- ikiller starts at end of table, walks towards iwalker; then tArgs is compressed
-- iwalker steps 1 up in the freshly compressed table
-- Used: iArgs is sorted, and order stays same. compress does not change that.
--------------------------------------------------------------------------------
local function applyRemoveDuplicates(tArgs)
local iR, iK -- iR = reader, iK = killer
local hit = false

	iR = 1
	while iR < #tArgs do
		iK = #tArgs -- will be counting downwards
		while iK > iR do
			if tArgs[iK] == tArgs[iR] then
				hit = true
				addPreviewMsg('Duplicate removed: ' .. tArgs[iR])
				table.remove(tArgs, iK)
				tTools.compressSparseArray(tArgs)
			end
			iK = iK - 1
		end
		tTools.compressSparseArray(tArgs)
		iR = iR + 1
	end

	if hit then
		addWarningCategory('D')
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- applyOmitRules
--
-- returns edited table, with Omit phraseID's removed
-- Omit rule is per GHS_Rev9E_0.pdf (2021)
--------------------------------------------------------------------------------
local function applyOmitRules(tArgs)
local tRules = GHSdata['tOmitRules']
	local hit = false
	
	for keep, omit in pairs(tRules) do
		if tTools.inArray(tArgs, omit) then
			if tTools.inArray(tArgs, keep) then
				hit = true
				for i, k in pairs(tArgs) do
					if k == omit then
						table.remove(tArgs, i)		
					end
				end
				addPreviewMsg(wlHelpPage('Omit Rules') .. ': keep ' .. keep .. ', omit ' .. omit)
			end
		end
	end
	if hit then
		tTools.compressSparseArray(tArgs)
		addWarningCategory('O')
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- label H-phrases or P-phrases
--------------------------------------------------------------------------------
local function PHlabel()
	if tArgName['setID'] == 'GHS' then
		return 'GHS phrases'
	else
		return tArgName['setID'] .. '-phrases'
	end
end

--------------------------------------------------------------------------------
-- inMono
--
-- Use mono font-family (from: Template:Mono)
--------------------------------------------------------------------------------
local function inMono(s)
	if s == nil then s = '' end
	return '<span class="monospaced" style="font-family: monospace;">' .. s .. '</span>'
end

--------------------------------------------------------------------------------
-- wlInlineTag
--
-- Returns <sup>[?]</sup> with wikilink to [[helppage#section|errormessage]]
--------------------------------------------------------------------------------
local function wlInlineTag(phraseID)
	local sMsg
	sMsg = '<sup><span class="noprint Inline-Template">&#91;<i>'
				.. wlHelpPage(PHlabel(), '<span title="' 
									.. PHlabel() .. ': '
									.. phraseID
									.. ' not found'
									.. '">?</span>')
				.. '</i>&#93;</span></sup>'
	return sMsg
end

--------------------------------------------------------------------------------
-- errorPhraseIDnotFound
--
-- Returns single value when error (not found in list):
-- plain value + inline warning [?] (linked) + error cat (mainsp) + preview warning
--------------------------------------------------------------------------------
local function errorPhraseIDnotFound(phraseID)
	if phraseID == nil then phraseID = '' end
	
	local inlineTag = wlInlineTag(phraseID)
	local previewMsg = wlHelpPage(PHlabel()) .. ': \"' .. phraseID .. '\" not found'
	addPreviewMsg(previewMsg)
	addErrorCategory()
	
	return phraseID .. inlineTag
end

--------------------------------------------------------------------------------
-- errorHPsetIDnotFound
--
-- setID H or P could not be found
--------------------------------------------------------------------------------
local function errorHPsetIDnotFound()
	local sMsg
	sMsg = wlHelpPage('', PHlabel())
			.. ': "H" or "P" set id not found' 
			.. ' (please use form like "|H200" or "|P300+P301")'
	addPreviewMsg(sMsg)
	addErrorCategory('?')
	return showPreviewMsg()
end

--------------------------------------------------------------------------------
-- errorHPsetIDmissing
--
-- parameter |setid= to be used
--------------------------------------------------------------------------------
local function errorHPsetIDmissing()
	local sMsg
	sMsg = wlHelpPage( '', PHlabel())
			.. ': "H" or "P" set id not found,' 
			.. ' please use |setid=... (H or P)'
	addPreviewMsg(sMsg)
	return
end

--------------------------------------------------------------------------------
-- formatPhraseAbbr
--
-- format phraseID and text, for abbr-form (infobox list form)
--------------------------------------------------------------------------------
local function formatPhraseAbbr(phraseID, sPhrase)
	return '<abbr class="abbr" title=" ' .. phraseID .. ': ' .. sPhrase .. '">'
				.. phraseID 
				.. '</abbr>'
end

--------------------------------------------------------------------------------
-- formatPhraseInline
--
-- format phraseID and text, for inline form (in sentence)
-- adds "quotes"
--------------------------------------------------------------------------------
local function formatPhraseInline(phraseID, sPhrase)
	return inMono(phraseID) .. ': \"' .. sPhrase .. '\"'
end

--------------------------------------------------------------------------------
-- formatPhraseList
--
-- as inline, but no "quotes" added.
--------------------------------------------------------------------------------
local function formatPhraseList(phraseID, sPhrase)
	return inMono(phraseID) .. ': ' .. sPhrase
end

--------------------------------------------------------------------------------
-- getSetID
--
-- Determines setID (expected either 'H' or 'P')
-- First route is: read |setid=
-- When |setid= is not set, 
--		it looks for a first parameter that has an H of P prefix (in |P201|P202|...)
--		when not found, 'GHS' is retured
-- In one call, P and H numbers can *not* be mixed
--		so "|H201|P202|" will cause error "P202 not found" (... in H-list)
--------------------------------------------------------------------------------
local function getSetID(tArgs)
	local setIDfound = 'GHS'
	local paramsetID = tArgs['setid'] or nil
	
	if (paramsetID ~= nil) and (paramsetID == 'P' or paramsetID == 'H') then
		setIDfound = paramsetID
	else
		local initial = nil
		for i, v in ipairs(tArgs) do
			initial = mw.ustring.match(v, '^[PH]')
			if initial ~=nil then
				setIDfound = initial
				break
			end
		end
	end
	return setIDfound
end

--------------------------------------------------------------------------------
-- getListType
--
-- Checks list format, including those from Module:List
--------------------------------------------------------------------------------
local function getListType(tArgs)
	local listTypes = {
	['abbr'] = true,
	['bulleted'] = true,
	['unbulleted'] = true,
	['horizontal'] = true,
	['ordered'] = true,
	['horizontal_ordered'] = true,
	['horizontal ordered'] = true,
	['inline'] = true
	}
	local sListType = tArgs['listtype'] or 'abbr'

	if sListType == '' or sListType == 'abbr' then
		return 'abbr'
	elseif listTypes[sListType] == true then
		if sListType == 'horizontal ordered' then
			sListType = 'horizontal_ordered'
		end
		return sListType
	else 
		sListType = 'abbr'
	end
	return sListType
end

--------------------------------------------------------------------------------
-- getDoOmitRules
--------------------------------------------------------------------------------
local function getDoOmitRules(tArgs)
	local b = yesno(tArgs['omit'], true)
	
	if b == nil then b = true end

	return yesno(b, true)
end

--------------------------------------------------------------------------------
-- prepareArgs
--
-- First: determine setID (from |setID= OR from prefixes in parameters)
-- Then: clean up & format phrase IDs (=unnamed parameters)
--		remove bad characters, create H/P pattern "H201", "P310+P302"
-- straight array, no nil's, sorted
--------------------------------------------------------------------------------
local function prepareArgs(tArgs)

	tArgName['setID'] = getSetID(tArgs)
	tArgName['listtype'] = getListType(tArgs)
	tArgName['omit'] = getDoOmitRules(tArgs)

	tArgs = tTools.compressSparseArray(tArgs) -- removes all named args
	if string.len(tArgName['setID']) == 1 and #tArgs > 0 then
		for i, v in ipairs(tArgs) do
			v = mw.text.decode(v)
			v = mw.ustring.gsub(v, '[^%d%+A-Za-z]', '')
			v = mw.ustring.gsub(v, '^(%d)', tArgName['setID'] .. '%1')
			v = mw.ustring.gsub(v, '%+(%d)', '+' .. tArgName['setID'] .. '%1')
			tArgs[i] = v
		end
		table.sort(tArgs)
	end
	return tArgs
end

--------------------------------------------------------------------------------
-- listAll
--
-- Returns wikitable rows for each phrase id.
-- requires |setID=P/H
-- returns full list, all phrases, for a setID
-- 2-columns wikitable, sorted, sortable, anchor like "H201" for each
--------------------------------------------------------------------------------
function r.listAll(frame)
local newArgs = getArgs(frame)
local tL = {}

	prepareArgs(newArgs)
	
	local tRead
	if tArgName['setID'] == 'H' then
		tRead = GHSdata['Hphrases']
	elseif tArgName['setID'] == 'P' then
		tRead = GHSdata['Pphrases']
	else 
		errorHPsetIDmissing()
		return  showPreviewMsg()
	end

	-- Intermediate table t2 to maintain order; read from original table (/data)
	local t2 = {}
	local iPh
	for s, v in pairs(tRead) do
		iPh = tonumber(mw.ustring.match(s, '[PH](%d%d%d)'))
		if string.len(s) > 4 then
			iPh = tTools.size(t2) + 1
		end
		table.insert(t2, iPh, s)
	end
	t2 = tTools.compressSparseArray(t2)
	table.sort(t2)

	local sTR, v, sAnchor
	-- i = array index, s = phraseID, v = phrase text
	for i, s in ipairs(t2) do
		v = tRead[s]
		sAnchor = '<span class="anchor" id="' .. s .. '"></span>'
		sTR = '|- ' .. sAnchor .. '\n| datasortvalue="' .. i .. '" | <span style="font-family: monospace;">' .. s .. '</span> || ' .. v
		table.insert(tL, sTR)
	end

	return table.concat(tL, '\n')
end

--------------------------------------------------------------------------------
-- numberOfPhrases
--
-- Documentation
-- requires |setID=H/P
-- Returns number of phrases, in format
--	"GHS H-phrases (123)"
--------------------------------------------------------------------------------
function r.numberOfPhrases(frame)
	local newArgs = getArgs(frame)

	prepareArgs(newArgs)

	local iT
	if tArgName['setID'] == 'H' then
		iT = tTools.size(GHSdata['Hphrases'])
	elseif tArgName['setID'] == 'P' then
		iT = tTools.size(GHSdata['Pphrases'])
	else
		errorHPsetIDmissing()
		return showPreviewMsg()
	end

	return 'GHS ' .. PHlabel() .. ' <span style="font-weight: normal;">(' .. tostring(iT) .. ')</span>'
end

--------------------------------------------------------------------------------
-- listOmitRules
--
-- self-documentation
--------------------------------------------------------------------------------
function r.listOmitRules()
local tRules = GHSdata['tOmitRules']
local tL = {}
local s

	s = wlHelpPage('Omit Rules')
		.. ': when the <i>keep</i> ID is present, do not show the <i>omit</i> ID phrase'
	table.insert(tL, s)
	for keep, omit in pairs (tRules) do
		s = '&bull; keep ' .. inMono(keep) .. ', omit ' .. inMono(omit)
		table.insert(tL, s)
	end
	return table.concat(tL, '<br/>')
end

--------------------------------------------------------------------------------
-- _main
--
-- processes setID (H, P) and phrase codes
--		error:	setID not P, H
--				code not found
-- cannot mix H and P phrases
-- reads phrases from /data H or P phrases tables
-- formats phrase (abbreviation, abbr-title, phraseID)
--------------------------------------------------------------------------------
function r._main(tArgs)

	tArgs = prepareArgs(tArgs)
	
	if #tArgs == 0 then
		return showPreviewMsg() -- no content
	elseif tArgName['setID'] == 'GHS' then
		return errorHPsetIDnotFound()
	end

	tArgs = applyRemoveDuplicates(tArgs)
	if tArgName['omit'] then
		tArgs = applyOmitRules(tArgs)
	end

	local formatterF
	if tArgName['listtype'] == 'abbr' then
		formatterF = formatPhraseAbbr
	elseif tArgName['listtype'] == 'inline' then
		formatterF = formatPhraseInline
	else --- Module:List options
		formatterF = formatPhraseList
	end
	
	local tReadD = {}
	if tArgName['setID'] == 'H' then
		tReadD = GHSdata['Hphrases']
	elseif tArgName['setID'] == 'P' then
		tReadD = GHSdata['Pphrases']
	else
		return showPreviewMsg()
	end

	local sPhrase
	local tR = {}
	for i, v in ipairs(tArgs) do
		sPhrase = tReadD[v]
		if sPhrase == nil then
			table.insert(tR, errorPhraseIDnotFound(tostring(v)))
		else
			table.insert(tR, formatterF(v, sPhrase))
		end
	end

	if tArgName['listtype'] == 'abbr' then
		return table.concat(tR, ', ') .. showPreviewMsg()
	elseif tArgName['listtype'] == 'inline' then
		return table.concat(tR, ', ') .. showPreviewMsg()
	else
		local mList = require('Module:List')
		return mList[tArgName['listtype']](tR) .. showPreviewMsg()
	end
end

--------------------------------------------------------------------------------
-- main
--
-- handles template input frame, then calls generic _main() function
-- To be invoked from {{template}}
--------------------------------------------------------------------------------
function r.main(frame)
local newArgs = getArgs(frame)
	return r._main(newArgs) 
end


return r