Difference between revisions of "Module:Track gauge"

From blackwiki
Jump to navigation Jump to search
blackwiki>DePiep
(Apply /sandbox changes. See Template talk:RailGauge#Code changes 6 July 2014.)
m (36 revisions imported)
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
-- This module implements the {{RailGauge}} template.
+
-- This module implements the {{Track gauge}} template.
-- Data is in Module:RailGauge/data and in Module:RailGauge/extra
+
-- Data is in Module:Track gauge/data
 
local p = {}
 
local p = {}
 
local gaugeDataAll = nil
 
local gaugeDataAll = nil
local gaugeDataExtra = nil
+
local dataPageName = 'Module:Track gauge/data' -- set /data/sandbox here
local dataPageName = 'Module:RailGauge/data' -- sandbox here
 
local dataPageExtra = 'Module:RailGauge/extra' -- sandbox here
 
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
 
-- prepareArgs -- Normalise Arguments coming from an #invoke or from a module
 
-- prepareArgs -- Normalise Arguments coming from an #invoke or from a module
Line 86: Line 84:
 
end
 
end
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
-- getRgEntry -- Find entry data for a single gauge (alias)
+
-- getTrackGaugeEntry -- Find entry data for a single gauge (alias)
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
function p.getRgEntry(searchAlias)
+
function p.getTrackGaugeEntry(searchAlias)
 
gaugeDataAll = mw.loadData(dataPageName)
 
gaugeDataAll = mw.loadData(dataPageName)
 
if searchAlias == '' then
 
if searchAlias == '' then
 
return nil
 
return nil
 
end
 
end
local rgEntry = nil
+
local tgEntry = nil
for i, rgEntry in ipairs(gaugeDataAll) do
+
for i, tgEntry in ipairs(gaugeDataAll) do
for j, alias in ipairs(rgEntry.aliases) do
+
for j, alias in ipairs(tgEntry.aliases) do
 
if alias == searchAlias then
 
if alias == searchAlias then
return rgEntry
+
return tgEntry
end
 
end
 
end
 
-- No hit, so seach in datapage /extra
 
rgEntry = nil
 
gaugeDataExtra = mw.loadData(dataPageExtra)
 
for i, rgEntry in ipairs(gaugeDataExtra) do
 
for j, alias in ipairs(rgEntry.aliases) do
 
if alias == searchAlias then
 
return rgEntry
 
 
end
 
end
 
end
 
end
Line 130: Line 118:
 
-- catMentions -- Wikicode for "article mentions gauge" categories
 
-- catMentions -- Wikicode for "article mentions gauge" categories
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
function p.catMentions(rgEntry, sortlabel, doReturn)
+
function p.catMentions(tgEntry, sortlabel, doReturn)
 
local ns = 'Category:'
 
local ns = 'Category:'
 
local cat
 
local cat
  
if rgEntry == nil then
+
if tgEntry == nil then
cat = 'Articles that mention a specific rail gauge' -- Parent, the container cat
+
-- Parent, the container cat
 +
cat = 'Articles that mention a specific track gauge'
 
else
 
else
cat = 'Articles that mention rail gauge size ' .. rgEntry.id .. ' mm'
+
cat = 'Articles that mention track gauge ' .. tgEntry.id .. ' mm'
 
end
 
end
 
-- Argument 'label' can be used to add a catsort. Catsort is not used (as of 20 May 2014)
 
-- Argument 'label' can be used to add a catsort. Catsort is not used (as of 20 May 2014)
Line 162: Line 151:
 
-- formatImp -- Formats imperial units size into a single text element
 
-- formatImp -- Formats imperial units size into a single text element
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
function p.formatImp(rgEntry, measurementToLink, setNowrap, addUnitlink)
+
function p.formatImp(tgEntry, measurementToLink, setNowrap, addUnitlink)
 
local ret = {}
 
local ret = {}
local ft = rgEntry.ft
+
local ft = tgEntry.ft
 
if ft then
 
if ft then
 
local ftlink = addUnitlink and measurementToLink ~= 'imp' and '[[Foot (unit)|ft]]' or 'ft'
 
local ftlink = addUnitlink and measurementToLink ~= 'imp' and '[[Foot (unit)|ft]]' or 'ft'
 
table.insert(ret, mw.ustring.format('%s %s', ft, ftlink))
 
table.insert(ret, mw.ustring.format('%s %s', ft, ftlink))
 
end
 
end
local inches = rgEntry['in']
+
local inches = tgEntry['in']
local num = rgEntry.num
+
local num = tgEntry.num
local den = rgEntry.den
+
local den = tgEntry.den
 
if inches and not num and not den then
 
if inches and not num and not den then
 
table.insert(ret, inches)
 
table.insert(ret, inches)
Line 187: Line 176:
 
gaugeSize = table.concat(ret, ' ')
 
gaugeSize = table.concat(ret, ' ')
 
end
 
end
if measurementToLink == 'imp' and rgEntry.pagename ~= nil then
+
if measurementToLink == 'imp' and tgEntry.pagename ~= nil then
return mw.ustring.format('[[%s|%s]]', rgEntry.pagename, gaugeSize)
+
return mw.ustring.format('[[%s|%s]]', tgEntry.pagename, gaugeSize)
 
else
 
else
 
return gaugeSize
 
return gaugeSize
Line 196: Line 185:
 
-- formatMet -- Formats metric measurements into a single formatted text element. Public for autodocument
 
-- formatMet -- Formats metric measurements into a single formatted text element. Public for autodocument
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
function p.formatMet(rgEntry, measurementToLink, setNowrap, addUnitlink)
+
function p.formatMet(tgEntry, measurementToLink, setNowrap, addUnitlink)
local m = rgEntry.m
+
local m = tgEntry.m
 
local gaugeSize
 
local gaugeSize
 
if m then
 
if m then
Line 203: Line 192:
 
gaugeSize = mw.ustring.format('%s %s', m, mUnit)
 
gaugeSize = mw.ustring.format('%s %s', m, mUnit)
 
else
 
else
local mm = rgEntry.mm
+
local mm = tgEntry.mm
 
mm = tonumber(mm)
 
mm = tonumber(mm)
 
if mm then
 
if mm then
Line 214: Line 203:
 
gaugeSize = noWrap(gaugeSize)
 
gaugeSize = noWrap(gaugeSize)
 
end
 
end
if measurementToLink == 'met' and rgEntry.pagename ~= nil then
+
if measurementToLink == 'met' and tgEntry.pagename ~= nil then
return mw.ustring.format('[[%s|%s]]', rgEntry.pagename, gaugeSize)
+
return mw.ustring.format('[[%s|%s]]', tgEntry.pagename, gaugeSize)
 
else
 
else
 
return gaugeSize
 
return gaugeSize
Line 223: Line 212:
 
-- formatAltName
 
-- formatAltName
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
function formatAltName(rgEntry, addArticleLink, disp, setNowrap)
+
function formatAltName(tgEntry, addGaugeName, addGaugeNameLink, disp, setNowrap, engvar)
-- Asserted: al=on
+
-- Assumed: at least one to add is true.
if rgEntry.name == nil then
+
if tgEntry.name == nil then
 +
-- Not checked: link does exist alone
 
return ''
 
return ''
 
end
 
end
 
local retAlt = {}
 
local retAlt = {}
 
if disp == 'br' then
 
if disp == 'br' then
table.insert(retAlt, '<br>')
+
table.insert(retAlt, '<br />')
 
else
 
else
 
table.insert(retAlt, ' ')
 
table.insert(retAlt, ' ')
Line 237: Line 227:
 
table.insert(retAlt, '<span class="nowrap">')
 
table.insert(retAlt, '<span class="nowrap">')
 
end
 
end
if addArticleLink and rgEntry.link then -- If not defined then fallback to unlinked name
+
if addGaugeNameLink then
table.insert(retAlt, rgEntry.link)
+
if engvar == 'en-us' then
else
+
-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
table.insert(retAlt, rgEntry.name)
+
table.insert(retAlt, tgEntry.en_US_link or tgEntry.link or tgEntry.name)
 +
else
 +
table.insert(retAlt, tgEntry.link or tgEntry.name)
 +
end
 +
else -- so must be unlinked .name to add
 +
if engvar == 'en-us' then
 +
-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
 +
table.insert(retAlt, tgEntry.en_US_name or tgEntry.name)
 +
else
 +
table.insert(retAlt, tgEntry.name)
 +
end
 
end
 
end
 
if setNowrap then --close tag
 
if setNowrap then --close tag
Line 251: Line 251:
 
-----------------------------------------------------------------------------------
 
-----------------------------------------------------------------------------------
 
function p.main(frame)
 
function p.main(frame)
-- In general: rgEntry (from RG/data) is passed to the functions, arguments are processed here.
+
-- In general: the tgEntry object (from TG/data) is passed to the functions, while arguments are processed here.
 
local title = mw.title.getCurrentTitle()
 
local title = mw.title.getCurrentTitle()
 
local args = prepareArgs(frame)
 
local args = prepareArgs(frame)
local rgEntry = p.getRgEntry(args.searchAlias)
+
local tgEntry = p.getTrackGaugeEntry(args.searchAlias)
 +
 
 +
-- Categorise & preview warning when no track gauge definition was found.
 +
if tgEntry == nil then
 +
local input = args[1] or ''
 +
local errorTail = ''
 +
 +
if frame:preprocess("{{REVISIONID}}") == "" then
 +
errorTail = '<div class="hatnote" style="color:red"><strong>Warning:</strong> ' .. 'Track gauge ' .. (input .. ' ' or '') .. 'not in [[:Template:Track_gauge#List_of_defined_track_gauges|List of defined track gauges]] ([[Template talk:Track gauge|talk]]).' .. ' (This message is shown only in preview.)</div>'
 +
end
  
-- Categorise the page if no gauge information was found.
+
if title:inNamespaces(0, 14) then -- mainspace and category space
if rgEntry == nil then
+
errorTail = errorTail .. "[[Category:Articles using template 'Track gauge' with unrecognized input]]"
local category = ''
 
if title:inNamespaces(0, 14) then
 
local sort1
 
if (args[1] or '') == '' then -- Blank input, sort top.
 
sort1 = ' '
 
else
 
sort1 = args[1] .. ', '
 
end
 
category = mw.ustring.format(
 
'[[Category:Articles with template RailGauge with unrecognized input|%s%s]]',
 
sort1, title.text)
 
 
end
 
end
return (args[1] or '') .. category
+
return input .. errorTail
 
end
 
end
-- sandbox here: option to show "(RailGauge/sandbox is currently under construction)" message. (Comment out to make it idle)
+
 
-- return rgEntry.id .. ' <span style="font-size:85%; font-style:italic; font-family=courier">(RailGauge/sandbox is currently under construction)</span>'
+
-- Check and set args & tgEntry props: disp, first, nowrap, first
-- Check and set args & rgEntry props: disp, first, nowrap, first
 
 
local disp = args.disp or ''
 
local disp = args.disp or ''
local first = args.first or rgEntry.def1
+
local first = args.first or tgEntry.def1
 
local unitlink = args.unitlink or ''
 
local unitlink = args.unitlink or ''
 
local nowrap = args.nowrap or ''
 
local nowrap = args.nowrap or ''
Line 285: Line 282:
 
measurementToLink = first -- Can make metric text links to the imp linked page
 
measurementToLink = first -- Can make metric text links to the imp linked page
 
else
 
else
measurementToLink = rgEntry.def1 -- When first=swapped, this could link 2nd measure.
+
measurementToLink = tgEntry.def1 -- When first=swapped, this could link 2nd measure.
 
end
 
end
 
end
 
end
Line 297: Line 294:
 
if first == 'met' then
 
if first == 'met' then
 
table.insert(ret,
 
table.insert(ret,
p.formatMet(rgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
+
p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
 
else
 
else
 
table.insert(ret,
 
table.insert(ret,
p.formatImp(rgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
+
p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
 
end
 
end
 
-- The joint and the second measure
 
-- The joint and the second measure
Line 308: Line 305:
 
local closeDisp = ''
 
local closeDisp = ''
 
if disp == 's' or disp == '/' then
 
if disp == 's' or disp == '/' then
joinText = '/&#x200b;'
+
joinText = '&nbsp;/ ' --spaces
 
elseif disp == 'br' then
 
elseif disp == 'br' then
joinText = '<br>('
+
joinText = '<br />('
 
closeDisp = ')'
 
closeDisp = ')'
 
elseif disp == '[' or disp == '[]' then
 
elseif disp == '[' or disp == '[]' then
Line 324: Line 321:
 
if first ~= 'met' then
 
if first ~= 'met' then
 
table.insert(ret,
 
table.insert(ret,
p.formatMet(rgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
+
p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
 
else
 
else
 
table.insert(ret,
 
table.insert(ret,
p.formatImp(rgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
+
p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
 
end
 
end
 
table.insert(ret, closeDisp) -- Could be ''
 
table.insert(ret, closeDisp) -- Could be ''
Line 335: Line 332:
 
end
 
end
 
-- Alternative name
 
-- Alternative name
if args.al or args.allk ~= nil then
+
if args.al == 'on' or args.allk == 'on' then
 
local setNowrapAltname = (nowrap == '' or nowrap == 'on') -- Logic applied to prevent nested nowrap tags
 
local setNowrapAltname = (nowrap == '' or nowrap == 'on') -- Logic applied to prevent nested nowrap tags
table.insert(ret, formatAltName(rgEntry, args.allk == 'on', disp, setNowrapAltname))
+
table.insert(ret, formatAltName(tgEntry, args.al == 'on', args.allk == 'on', disp, setNowrapAltname, args.engvar))
 
end
 
end
 
-- Closing nowrap tag
 
-- Closing nowrap tag
Line 343: Line 340:
 
table.insert(ret, '</span>')
 
table.insert(ret, '</span>')
 
end
 
end
 +
 
-- Category mentionings (maintenance)
 
-- Category mentionings (maintenance)
if rgEntry.id == '1435' or (args.addcat or '') == 'no' then
+
if args.addcat or '' == 'no' then
 
-- No categorization
 
-- No categorization
 
elseif title:inNamespaces(0) then
 
elseif title:inNamespaces(0) then
table.insert(ret, p.catMentions(rgEntry))
+
-- switched off per [[Wikipedia:Categories_for_discussion/Log/2016_December_6#Category:Articles_that_mention_a_specific_track_gauge]]
 +
-- 2016-12-19
 +
-- table.insert(ret, p.catMentions(tgEntry))
 
end
 
end
 +
 
-- Now sting the table together
 
-- Now sting the table together
 
return table.concat(ret, '')
 
return table.concat(ret, '')
Line 354: Line 355:
  
 
return p
 
return p
 +
--20161219: maintenance categorisation switched off per CfD
 +
--20170602: fix bug, show name when al=on
 +
--20180708: show preview warning when gauge is not in list
 +
--20190124: with disp=/ (slash) value separator: surround by spaces

Latest revision as of 17:25, 29 September 2020

This module implements the {{Track gauge}} template. Please see the template page for documentation on how to use the main TrackGauge function.

Gauge data

The gauge information is stored at Module:Track gauge/data; to add new gauges, see the instructions there.

Data checks

This module includes a function that checks the data page for errors. It is used with the following code:

{{#invoke:Track gauge/autodocument|checkData|name of data page}}

The first positional parameter is the name of the data page that you want to be checked. If this is omitted, the module checks Module:Track gauge/data.

Tracking/maintenance category


-- This module implements the {{Track gauge}} template.
-- Data is in Module:Track gauge/data
local p = {}
local gaugeDataAll = nil
local dataPageName = 'Module:Track gauge/data' -- set /data/sandbox here
-----------------------------------------------------------------------------------
-- prepareArgs -- Normalise Arguments coming from an #invoke or from a module
-----------------------------------------------------------------------------------
local function prepareArgs(frame)
	local origArgs
	if frame == mw.getCurrentFrame() then
		origArgs = frame:getParent().args
		for k, v in pairs(frame.args) do
			origArgs = frame.args
			break
		end
	else
		origArgs = frame
	end
	local args = {}
	-- searchAlias is the cleaned value of args[1]. args[1] is kept as rawInput for error message
	local searchAlias = ''
	local rawDisp
	for k, v in pairs(origArgs) do
		if tonumber(k) == nil then -- Named argment
			if k == 'disp' then
				rawDisp = v -- Keep raw disp input to pass through plain (wiki)text
				args[k] = mw.ustring.lower(v)
			elseif k == 'first' then
				v = mw.ustring.lower(v)
				if v == 'met' or v == 'metric' then
					v = 'met'
				elseif v == 'imp' or v == 'imperial' then
					v = 'imp'
				else k = 'trashparam_first' end
				args[k] = v
			elseif k == 'nowrap' or k == 'wrap' then -- wrap=y deprecated; reading: nowrap=off
				v = mw.ustring.lower(v)
				if v == '' or v == 'off' or v == 'on' or v == 'all' then
				elseif v == 'inline' or (k == 'wrap' and v == 'y') then
					v = 'off'
				else v = '' end
				args['nowrap'] = v
			else
				args[k] = mw.ustring.lower(v)
			end
		else
			args[k] = v -- Keep rawInput in [1] for error message
			if k == 1 then
			-- Unnamed argument, the alias to be searched
			-- Cleanup
				searchAlias = p.normaliseAliasInput(v)
			end
		end
	end
	args['searchAlias'] = searchAlias
	if rawDisp then args['rawDisp'] = rawDisp end
	return args
end
-----------------------------------------------------------------------------------
-- normaliseAliasInput
-----------------------------------------------------------------------------------
function p.normaliseAliasInput(aliasIn)
	local a
	a = mw.ustring.lower(mw.ustring.gsub(aliasIn, '[%s%,]', ''))
	a = mw.ustring.gsub(a, '&nbsp;', '')
	a = mw.ustring.gsub(a, 'gauge$', '')
	a = mw.ustring.gsub(a, "'", "ft")
	a = mw.ustring.gsub(a, '"', 'in')
	a = mw.ustring.gsub(a, '⁄', '/')
	a = mw.ustring.gsub(a, '&frasl;', '/')
	return a	
end
-----------------------------------------------------------------------------------
-- debugReturnArgs -- Debug function.
-----------------------------------------------------------------------------------
function p.debugReturnArgs(frame)
	local args = prepareArgs(frame)
	local retArgs = {}
	for k, a in pairs(args) do
		table.insert(retArgs, k .. '=' .. a)
	end
	return 'Args: ' .. table.concat(retArgs, '; ')
end
-----------------------------------------------------------------------------------
-- getTrackGaugeEntry -- Find entry data for a single gauge (alias)
-----------------------------------------------------------------------------------
function p.getTrackGaugeEntry(searchAlias)
	gaugeDataAll = mw.loadData(dataPageName)
	if searchAlias == '' then
		return nil
	end
	local tgEntry = nil
	for i, tgEntry in ipairs(gaugeDataAll) do
		for j, alias in ipairs(tgEntry.aliases) do
			if alias == searchAlias then
				return tgEntry
			end
		end
	end
end
-----------------------------------------------------------------------------------
-- noWrap -- Add span tags to prevent a string from wrapping.
-----------------------------------------------------------------------------------
local function noWrap(s)
	return mw.ustring.format('<span class="nowrap">%s</span>', s)
end
-----------------------------------------------------------------------------------
-- frac -- A slimmed-down version of the {{frac}} template (a nowrap is to be added with the unit)
-----------------------------------------------------------------------------------
local function frac(whole, num, den)
	return mw.ustring.format(
		'<span class="frac">%s%s<sup>%s</sup>&frasl;<sub>%s</sub></span>',
		whole or '', whole and '<span class="visualhide">&nbsp;</span>' or '',
		num, den)
end
-----------------------------------------------------------------------------------
-- catMentions -- Wikicode for "article mentions gauge" categories
-----------------------------------------------------------------------------------
function p.catMentions(tgEntry, sortlabel, doReturn)
	local ns = 'Category:'
	local cat

	if tgEntry == nil then
		-- Parent, the container cat
		cat = 'Articles that mention a specific track gauge'
	else
		cat = 'Articles that mention track gauge ' .. tgEntry.id .. ' mm'
	end
	-- Argument 'label' can be used to add a catsort. Catsort is not used (as of 20 May 2014)
	if sortlabel ~= nil then
		sortlabel = '|' .. sortlabel
	else
		sortlabel = ''
	end
	if doReturn ~= nil then
		if doReturn == 'fullpagename' then
			return ns .. cat
		elseif doReturn == 'pagename' then -- plaintext, no namespace
			return cat
		elseif doReturn == 'show' then -- colontrick
			return '[[:' .. ns .. cat .. sortlabel .. ']]'
		else -- unknown arg value
			return ns .. cat
		end
	else -- Returns straight categorisation (wikitext)
		return '[[' .. ns .. cat .. sortlabel .. ']]'
	end
end
-----------------------------------------------------------------------------------
-- formatImp -- Formats imperial units size into a single text element
-----------------------------------------------------------------------------------
function p.formatImp(tgEntry, measurementToLink, setNowrap, addUnitlink)
	local ret = {}
	local ft = tgEntry.ft
	if ft then
		local ftlink = addUnitlink and measurementToLink ~= 'imp' and '[[Foot (unit)|ft]]' or 'ft'
		table.insert(ret, mw.ustring.format('%s&nbsp;%s', ft, ftlink))
	end
	local inches = tgEntry['in']
	local num = tgEntry.num
	local den = tgEntry.den
	if inches and not num and not den then
		table.insert(ret, inches)
	elseif num and den then
		table.insert(ret, frac(inches, num, den))
	end
	if inches or num and den then
		local incheslink = addUnitlink and measurementToLink ~= 'imp' and '[[inch|in]]' or 'in'
		table.insert(ret, incheslink)
	end
	local gaugeSize
	if setNowrap then
		gaugeSize = noWrap(table.concat(ret, '&nbsp;'))
	else
		gaugeSize = table.concat(ret, '&nbsp;')
	end
	if measurementToLink == 'imp' and tgEntry.pagename ~= nil then
		return mw.ustring.format('[[%s|%s]]', tgEntry.pagename, gaugeSize)
	else
		return gaugeSize
	end
end
-----------------------------------------------------------------------------------
-- formatMet -- Formats metric measurements into a single formatted text element. Public for autodocument
-----------------------------------------------------------------------------------
function p.formatMet(tgEntry, measurementToLink, setNowrap, addUnitlink)
	local m = tgEntry.m
	local gaugeSize
	if m then
		local mUnit = addUnitlink and measurementToLink ~= 'met' and '[[metre|m]]' or 'm'
		gaugeSize = mw.ustring.format('%s&nbsp;%s', m, mUnit)
	else
		local mm = tgEntry.mm
		mm = tonumber(mm)
		if mm then
			mm = mw.getContentLanguage():formatNum(mm)
		end
		local mmUnit = addUnitlink and measurementToLink ~= 'met' and '[[millimetre|mm]]' or 'mm'
		gaugeSize = mw.ustring.format('%s&nbsp;%s', mm, mmUnit)
	end
	if setNowrap then
		gaugeSize = noWrap(gaugeSize)
	end
	if measurementToLink == 'met' and tgEntry.pagename ~= nil then
		return mw.ustring.format('[[%s|%s]]', tgEntry.pagename, gaugeSize)
	else
		return gaugeSize
	end
end
-----------------------------------------------------------------------------------
-- formatAltName
-----------------------------------------------------------------------------------
function formatAltName(tgEntry, addGaugeName, addGaugeNameLink, disp, setNowrap, engvar)
	-- Assumed: at least one to add is true.
	if tgEntry.name == nil then
		-- Not checked: link does exist alone
		return ''
	end
	local retAlt = {}
	if disp == 'br' then
		table.insert(retAlt, '<br />')
	else
		table.insert(retAlt, ' ')
	end
	if setNowrap then
		table.insert(retAlt, '<span class="nowrap">')
	end
	if addGaugeNameLink then
		if engvar == 'en-us' then
			-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
			table.insert(retAlt, tgEntry.en_US_link or tgEntry.link or tgEntry.name)
		else
			table.insert(retAlt, tgEntry.link or tgEntry.name)
		end
	else -- so must be unlinked .name to add
			if engvar == 'en-us' then
			-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
			table.insert(retAlt, tgEntry.en_US_name or tgEntry.name)
		else
			table.insert(retAlt, tgEntry.name)
		end
	end
	if setNowrap then --close tag
		table.insert(retAlt, '</span>')
	end
	return table.concat(retAlt, '')
end
-----------------------------------------------------------------------------------
-- main -- The basic module
-----------------------------------------------------------------------------------
function p.main(frame)
	-- In general: the tgEntry object (from TG/data) is passed to the functions, while arguments are processed here.
	local title = mw.title.getCurrentTitle()
	local args = prepareArgs(frame)
	local tgEntry = p.getTrackGaugeEntry(args.searchAlias)

	-- Categorise & preview warning when no track gauge definition was found.
	if tgEntry == nil then
		local input = args[1] or ''
		local errorTail = ''
		
		if frame:preprocess("{{REVISIONID}}") == "" then 
				errorTail = '<div class="hatnote" style="color:red"><strong>Warning:</strong> ' .. 'Track gauge ' .. (input .. ' ' or '') .. 'not in [[:Template:Track_gauge#List_of_defined_track_gauges|List of defined track gauges]] ([[Template talk:Track gauge|talk]]).' .. ' (This message is shown only in preview.)</div>'
		end

		if title:inNamespaces(0, 14) then -- mainspace and category space
			errorTail = errorTail .. "[[Category:Articles using template 'Track gauge' with unrecognized input]]"
		end
		return input .. errorTail
	end

	-- Check and set args & tgEntry props: disp, first, nowrap, first
	local disp = args.disp or ''
	local first = args.first or tgEntry.def1
	local unitlink = args.unitlink or ''
	local nowrap = args.nowrap or ''
	local setNowrapElement = (nowrap == '' or nowrap == 'off') -- To prevent nested nowrap tags
	local measurementToLink
	if args.lk == 'on' then
		if disp == '1' then
			measurementToLink = first -- Can make metric text links to the imp linked page
		else
			measurementToLink = tgEntry.def1 -- When first=swapped, this could link 2nd measure.
		end
	end
	-- String the text elements together (compose the return table)
	local ret = {}
	-- nowrap opening tag
	if nowrap == 'all' or nowrap == 'on' then
		table.insert(ret, '<span class="nowrap">')
	end
	-- First measure
	if first == 'met' then
		table.insert(ret,
			p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
	else
		table.insert(ret,
			p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
	end
	-- The joint and the second measure
	if disp == '1' then
	else
		local joinText = ''
		local closeDisp = ''
		if disp == 's' or disp == '/' then
			joinText = '&nbsp;/ ' --spaces
		elseif disp == 'br' then
			joinText = '<br />('
			closeDisp = ')'
		elseif disp == '[' or disp == '[]' then
			joinText = ' ['
			closeDisp = ']'
		elseif disp ~= '' then -- Is anytext
			joinText = ' ' .. args['rawDisp'] .. ' '
		else
			joinText = ' ('
			closeDisp = ')'
		end
		table.insert(ret, joinText)
		if first ~= 'met' then
			table.insert(ret,
				p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
		else
			table.insert(ret,
				p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
		end
		table.insert(ret, closeDisp) -- Could be ''
	end
	if nowrap == 'on' then -- Closing tag
		table.insert(ret, '</span>')
	end
	-- Alternative name
	if args.al == 'on' or args.allk == 'on' then
		local setNowrapAltname = (nowrap == '' or nowrap == 'on') -- Logic applied to prevent nested nowrap tags
		table.insert(ret, formatAltName(tgEntry, args.al == 'on', args.allk == 'on', disp, setNowrapAltname, args.engvar))
	end
	-- Closing nowrap tag
	if nowrap == 'all' then
		table.insert(ret, '</span>')
	end
	
	-- Category mentionings (maintenance)
	if args.addcat or '' == 'no' then
		-- No categorization
	elseif title:inNamespaces(0) then
		-- switched off per [[Wikipedia:Categories_for_discussion/Log/2016_December_6#Category:Articles_that_mention_a_specific_track_gauge]]
		-- 2016-12-19
		-- table.insert(ret, p.catMentions(tgEntry))
	end

	-- Now sting the table together
	return table.concat(ret, '')
end

return p
--20161219: maintenance categorisation switched off per CfD
--20170602: fix bug, show name when al=on
--20180708: show preview warning when gauge is not in list
--20190124: with disp=/ (slash) value separator: surround by spaces