Soft launch: Soldier biographies and research notes vary in completeness. Prefer class-roster, NARA, newspapers, and other cited sources for contested facts — treat Research notes as leads, not settled history. Anyone can correct a page; contact us with questions.

Module:Soldier

From Ritchie Boys Wiki
Revision as of 05:28, 18 August 2026 by Admin (talk | contribs) (wikipedia_layout)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Soldier/doc

local p = {}

local function trim(s)
	return mw.text.trim(tostring(s or ''))
end

local function parentArg(frame, name)
	local parent = frame:getParent()
	if parent and parent.args[name] then
		return trim(parent.args[name])
	end
	return trim(frame.args[name])
end

local function titleCase(s)
	s = trim(s)
	if s == '' then
		return s
	end
	s = mw.ustring.lower(s)
	return mw.ustring.gsub(s, "(%a)([%w']*)", function(first, rest)
		return mw.ustring.upper(first) .. rest
	end)
end

local function containsIgnoreCase(haystack, needle)
	return mw.ustring.find(mw.ustring.lower(haystack), mw.ustring.lower(needle), 1, true) ~= nil
end

local function displayName(frame)
	local first = parentArg(frame, 'first')
	local middle = parentArg(frame, 'middle')
	local surname = parentArg(frame, 'surname')
	local suffix = parentArg(frame, 'suffix')
	local parts = {}
	if first ~= '' then
		table.insert(parts, first)
	end
	if middle ~= '' then
		table.insert(parts, middle)
	end
	if surname ~= '' then
		table.insert(parts, surname)
	end
	local name = table.concat(parts, ' ')
	if suffix ~= '' then
		if name ~= '' then
			name = name .. ', ' .. suffix
		else
			name = suffix
		end
	end
	if name == '' then
		name = 'This soldier'
	end
	return name
end

local function classLinkList(raw, withPrefix)
	local out = {}
	for part in mw.text.gsplit(raw, ';', true) do
		part = trim(part)
		if part ~= '' then
			if withPrefix then
				table.insert(out, string.format('[[Class %s]]', part))
			else
				table.insert(out, string.format('[[Class %s|%s]]', part, part))
			end
		end
	end
	return out
end

local function addHeader(tbl, text)
	tbl:tag('tr'):tag('th')
		:attr('colspan', '2')
		:addClass('infobox-header')
		:wikitext(text)
end

local function addRow(tbl, label, value, dataClass)
	if trim(value) == '' then
		return
	end
	local tr = tbl:tag('tr')
	tr:tag('th'):addClass('infobox-label'):wikitext(label)
	local td = tr:tag('td'):addClass('infobox-data')
	if dataClass and dataClass ~= '' then
		td:addClass(dataClass)
	end
	td:wikitext(value)
end

function p.displayName(frame)
	return displayName(frame)
end

function p.classLinks(frame)
	return table.concat(classLinkList(parentArg(frame, 'class_number'), false), ', ')
end

function p.infobox(frame)
	local name = displayName(frame)
	local tbl = mw.html.create('table')
	tbl:addClass('infobox'):addClass('vcard'):addClass('soldier-infobox')

	tbl:tag('tr'):tag('th')
		:attr('colspan', '2')
		:addClass('infobox-above fn')
		:wikitext(name)

	local photo = parentArg(frame, 'photo')
	if photo ~= '' then
		local size = parentArg(frame, 'image_size')
		if size == '' then
			size = '220px'
		end
		local alt = parentArg(frame, 'alt')
		if alt == '' then
			alt = name
		end
		local td = tbl:tag('tr'):tag('td')
			:attr('colspan', '2')
			:addClass('infobox-image')
		td:wikitext(string.format('[[File:%s|%s|alt=%s]]', photo, size, alt))
		local caption = parentArg(frame, 'caption')
		if caption ~= '' then
			td:tag('div'):addClass('infobox-caption'):wikitext(caption)
		end
	end

	local alias = parentArg(frame, 'alias')
	local birth = parentArg(frame, 'birth_year')
	local death = parentArg(frame, 'death_year')
	local nativity = parentArg(frame, 'nativity')
	local religion = parentArg(frame, 'religion')
	local marital = parentArg(frame, 'marital')
	local education = parentArg(frame, 'education')
	local occupation = parentArg(frame, 'occupation')
	local state = parentArg(frame, 'state')

	if alias ~= '' or birth ~= '' or death ~= '' or nativity ~= ''
		or religion ~= '' or marital ~= '' or education ~= ''
		or occupation ~= '' or state ~= '' then
		addHeader(tbl, 'Personal details')
	end

	addRow(tbl, 'Nickname', alias, 'nickname')

	if birth ~= '' then
		local born = birth
		if nativity ~= '' then
			born = born .. '<br />Nativity: ' .. nativity
		end
		addRow(tbl, 'Born', born)
	elseif nativity ~= '' then
		addRow(tbl, 'Nativity', nativity)
	end
	addRow(tbl, 'Died', death)
	addRow(tbl, 'Religion', religion)
	addRow(tbl, 'Spouse / marital', marital)
	addRow(tbl, 'Education', education)
	addRow(tbl, 'Occupation', occupation)
	if state ~= '' then
		addRow(tbl, 'State', titleCase(state))
	end

	addHeader(tbl, 'Military service')
	addRow(tbl, 'Allegiance', 'United States')
	local branch = parentArg(frame, 'class_branch')
	if branch == '' then
		branch = 'United States Army'
	end
	addRow(tbl, 'Branch', branch)
	addRow(tbl, 'ASN', parentArg(frame, 'asn'), 'serial')

	local rankFinal = parentArg(frame, 'rank_final')
	local classRank = parentArg(frame, 'class_rank')
	local rank = rankFinal
	if rank == '' then
		rank = classRank
	elseif classRank ~= '' and classRank ~= rankFinal then
		rank = rankFinal .. "<br />''At Ritchie:'' " .. classRank
	end
	addRow(tbl, 'Rank', rank)

	local classRaw = parentArg(frame, 'class_number')
	local classBits = classLinkList(classRaw, false)
	if #classBits > 0 then
		local camp = 'Class ' .. table.concat(classBits, ', ')
		local section = parentArg(frame, 'class_section')
		if section ~= '' then
			camp = camp .. '<br />Section ' .. section
		end
		local other = parentArg(frame, 'other_class')
		if other ~= '' then
			camp = camp .. '<br />Other: ' .. other
		end
		addRow(tbl, 'Camp Ritchie', camp)
	end

	local enlist = parentArg(frame, 'enlistment_place')
	if enlist ~= '' then
		addRow(tbl, 'Enlisted', titleCase(enlist))
	end
	addRow(tbl, 'Assignment', parentArg(frame, 'assignment'))
	addRow(tbl, 'Unit / division', parentArg(frame, 'division'))
	addRow(tbl, 'IPW (German)', parentArg(frame, 'ipw_ge'))
	addRow(tbl, 'IPW (Italian)', parentArg(frame, 'ipw_it'))
	addRow(tbl, 'Overseas', parentArg(frame, 'overseas'))
	addRow(tbl, 'Special', parentArg(frame, 'special'))
	addRow(tbl, 'LOC', parentArg(frame, 'loc'))

	local arrive = parentArg(frame, 'date_arrive')
	local depart = parentArg(frame, 'date_depart')
	if arrive ~= '' or depart ~= '' then
		local dates = {}
		if arrive ~= '' then
			table.insert(dates, 'Arrived ' .. arrive)
		end
		if depart ~= '' then
			table.insert(dates, 'Departed ' .. depart)
		end
		addRow(tbl, 'Service dates', table.concat(dates, '<br />'))
	end
	addRow(tbl, 'Certificate', parentArg(frame, 'certificate'))

	return tostring(tbl)
end

function p.lead(frame)
	local name = displayName(frame)
	local surname = parentArg(frame, 'surname')
	if surname == '' then
		surname = name
	end
	local birth = parentArg(frame, 'birth_year')
	local death = parentArg(frame, 'death_year')
	local dates = ''
	if birth ~= '' and death ~= '' then
		dates = string.format(' (%s – %s)', birth, death)
	elseif birth ~= '' then
		dates = string.format(' (born %s)', birth)
	elseif death ~= '' then
		dates = string.format(' (died %s)', death)
	end

	local classLinks = classLinkList(parentArg(frame, 'class_number'), true)
	local trained
	if #classLinks == 1 then
		trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1]
	elseif #classLinks > 1 then
		trained = ' who trained at [[Camp Ritchie]], Maryland, in classes ' .. table.concat(classLinks, ', ')
	else
		trained = ' associated with Camp Ritchie, Maryland'
	end

	local first = string.format(
		"'''%s'''%s was a United States Army soldier%s.",
		name,
		dates,
		trained
	)

	local more = {}
	local enlist = parentArg(frame, 'enlistment_place')
	local state = parentArg(frame, 'state')
	if enlist ~= '' then
		local place = titleCase(enlist)
		if state ~= '' then
			local stateTitle = titleCase(state)
			if not containsIgnoreCase(place, stateTitle) then
				place = place .. ', ' .. stateTitle
			end
		end
		table.insert(more, surname .. ' enlisted at ' .. place .. '.')
	elseif state ~= '' then
		table.insert(more, 'Records list ' .. titleCase(state) .. ' as the state of enlistment or residence.')
	end

	local rank = parentArg(frame, 'rank_final')
	if rank == '' then
		rank = parentArg(frame, 'class_rank')
	end
	if rank ~= '' then
		table.insert(more, 'Records list the rank as ' .. rank .. '.')
	end

	local assignment = parentArg(frame, 'assignment')
	if assignment ~= '' then
		table.insert(more, surname .. ' was assigned to ' .. assignment .. '.')
	end

	local ipw = {}
	local ge = parentArg(frame, 'ipw_ge')
	local it = parentArg(frame, 'ipw_it')
	if ge ~= '' then
		table.insert(ipw, 'German-language IPW team ' .. ge)
	end
	if it ~= '' then
		table.insert(ipw, 'Italian-language IPW team ' .. it)
	end
	if #ipw > 0 then
		table.insert(more, 'Interrogation duty included ' .. table.concat(ipw, ' and ') .. '.')
	end

	if #more == 0 then
		return first
	end
	return first .. '\n\n' .. table.concat(more, ' ')
end

return p