Categorize soldiers from MII codes in notes.
Place-name display formatting
Line 109: Line 109:


local SMALL_WORDS = {
local SMALL_WORDS = {
of = true, the = true, to = true, a = true, an = true, at = true, by = true,
and = true, of = true, the = true, for = true, to = true, in = true,
a = true, an = true, at = true, by = true, or = true,
}
}
SMALL_WORDS['and'] = true
SMALL_WORDS['for'] = true
SMALL_WORDS['in'] = true
SMALL_WORDS['or'] = true


local STATE_NAME = {
local STATE_NAME = {
Line 134: Line 131:
al = 'Alabama', ak = 'Alaska', az = 'Arizona', ar = 'Arkansas', ca = 'California',
al = 'Alabama', ak = 'Alaska', az = 'Arizona', ar = 'Arkansas', ca = 'California',
co = 'Colorado', ct = 'Connecticut', de = 'Delaware', fl = 'Florida', ga = 'Georgia',
co = 'Colorado', ct = 'Connecticut', de = 'Delaware', fl = 'Florida', ga = 'Georgia',
hi = 'Hawaii', id = 'Idaho', il = 'Illinois', ia = 'Iowa',
hi = 'Hawaii', id = 'Idaho', il = 'Illinois', ['in'] = 'Indiana', ia = 'Iowa',
ks = 'Kansas', ky = 'Kentucky', la = 'Louisiana', me = 'Maine', md = 'Maryland',
ks = 'Kansas', ky = 'Kentucky', la = 'Louisiana', me = 'Maine', md = 'Maryland',
ma = 'Massachusetts', mi = 'Michigan', mn = 'Minnesota', ms = 'Mississippi',
ma = 'Massachusetts', mi = 'Michigan', mn = 'Minnesota', ms = 'Mississippi',
mo = 'Missouri', mt = 'Montana', ne = 'Nebraska', nv = 'Nevada', nh = 'New Hampshire',
mo = 'Missouri', mt = 'Montana', ne = 'Nebraska', nv = 'Nevada', nh = 'New Hampshire',
nj = 'New Jersey', nm = 'New Mexico', ny = 'New York', nc = 'North Carolina',
nj = 'New Jersey', nm = 'New Mexico', ny = 'New York', nc = 'North Carolina',
nd = 'North Dakota', oh = 'Ohio', ok = 'Oklahoma', pa = 'Pennsylvania',
nd = 'North Dakota', oh = 'Ohio', ok = 'Oklahoma', ['or'] = 'Oregon', pa = 'Pennsylvania',
ri = 'Rhode Island', sc = 'South Carolina', sd = 'South Dakota', tn = 'Tennessee',
ri = 'Rhode Island', sc = 'South Carolina', sd = 'South Dakota', tn = 'Tennessee',
tx = 'Texas', ut = 'Utah', vt = 'Vermont', va = 'Virginia', wa = 'Washington',
tx = 'Texas', ut = 'Utah', vt = 'Vermont', va = 'Virginia', wa = 'Washington',
wv = 'West Virginia', wi = 'Wisconsin', wy = 'Wyoming', dc = 'Washington, D.C.',
wv = 'West Virginia', wi = 'Wisconsin', wy = 'Wyoming', dc = 'Washington, D.C.',
}
}
STATE_ABBR['in'] = 'Indiana'
STATE_ABBR['or'] = 'Oregon'


local TWO_WORD_STATE = {
local TWO_WORD_STATE = {
Line 161: Line 156:


local PLACE_PREP = {
local PLACE_PREP = {
at = true, from = true, near = true, of = true,
at = true, ['in'] = true, from = true, near = true, of = true,
}
}
PLACE_PREP['in'] = true


local function stateKey(w)
local function stateKey(w)
Line 216: Line 210:
local up = mw.ustring.upper(bare)
local up = mw.ustring.upper(bare)
if ACRONYMS[up] then
if ACRONYMS[up] then
local replaced = mw.ustring.gsub(w, bare, up, 1)
table.insert(out, mw.ustring.gsub(w, bare, up, 1))
table.insert(out, replaced)
else
else
local low = mw.ustring.lower(w)
local low = mw.ustring.lower(w)
Line 522: Line 515:
end
end
local tr = tbl:tag('tr')
local tr = tbl:tag('tr')
tr:tag('th')
tr:tag('th'):addClass('infobox-label'):wikitext(label)
:addClass('infobox-label')
local td = tr:tag('td'):addClass('infobox-data')
:css('display', 'table-cell')
:css('width', '38%')
:css('font-weight', 'bold')
:css('text-align', 'left')
:css('vertical-align', 'top')
:wikitext(label)
local td = tr:tag('td')
:addClass('infobox-data')
:css('display', 'table-cell')
:css('vertical-align', 'top')
if dataClass and dataClass ~= '' then
if dataClass and dataClass ~= '' then
td:addClass(dataClass)
td:addClass(dataClass)
Line 640: Line 623:
key = trim(key)
key = trim(key)
return RANK_MAP[key] or raw
return RANK_MAP[key] or raw
end
local BRANCH_MAP = {
['INF'] = 'Infantry',
['INFANTRY'] = 'Infantry',
['FA'] = 'Field Artillery',
['FIELD ARTILLERY'] = 'Field Artillery',
['CAC'] = 'Coast Artillery Corps',
['CA'] = 'Coast Artillery',
['COAST ARTILLERY'] = 'Coast Artillery',
['AC'] = 'Air Corps',
['AAF'] = 'Army Air Forces',
['AIR CORPS'] = 'Air Corps',
['QMC'] = 'Quartermaster Corps',
['QC'] = 'Quartermaster Corps',
['QUARTERMASTER'] = 'Quartermaster Corps',
['CAV'] = 'Cavalry',
['CAVALRY'] = 'Cavalry',
['CE'] = 'Corps of Engineers',
['ENG'] = 'Corps of Engineers',
['ENGINEERS'] = 'Corps of Engineers',
['CMP'] = 'Corps of Military Police',
['MP'] = 'Military Police',
['CWS'] = 'Chemical Warfare Service',
['AUS'] = 'Army of the United States',
['SC'] = 'Signal Corps',
['SIG'] = 'Signal Corps',
['SIG C'] = 'Signal Corps',
['SIGC'] = 'Signal Corps',
['SIGNAL CORPS'] = 'Signal Corps',
['ORD'] = 'Ordnance Department',
['ORDNANCE'] = 'Ordnance Department',
['MAC'] = 'Medical Administrative Corps',
['MC'] = 'Medical Corps',
['MD'] = 'Medical Department',
['TC'] = 'Transportation Corps',
['MI'] = 'Military Intelligence',
['MIS'] = 'Military Intelligence Service',
['INT'] = 'Intelligence',
['CIC'] = 'Counter Intelligence Corps',
['AGD'] = "Adjutant General's Department",
['USMC'] = 'United States Marine Corps',
['USMCR'] = 'United States Marine Corps Reserve',
['AA'] = 'Antiaircraft',
['AAA'] = 'Antiaircraft Artillery',
['TD'] = 'Tank Destroyer',
['FD'] = 'Finance Department',
['GSC'] = 'General Staff Corps',
['ARMD F'] = 'Armored Force',
['ARMD'] = 'Armored',
['ARMOR'] = 'Armor',
['SSF'] = 'Special Service Force',
['PA'] = 'Philippine Army',
['RCE'] = 'Royal Canadian Engineers',
['RCA'] = 'Royal Canadian Artillery',
['CHC'] = 'Chaplain Corps',
['CHP'] = 'Chaplain Corps',
['CAO'] = 'Civil Affairs',
['CAU'] = 'Civil Affairs',
}
local function expandBranchToken(raw)
raw = trim(raw)
if raw == '' then
return ''
end
local key = mw.ustring.upper(raw)
key = mw.ustring.gsub(key, '%.', '')
key = mw.ustring.gsub(key, '%s+', ' ')
key = trim(key)
if BRANCH_MAP[key] then
return BRANCH_MAP[key]
end
local left, right = mw.ustring.match(key, '^(.+) %((.+)%)$')
if left and right then
left = trim(left)
right = trim(right)
local leftExp = BRANCH_MAP[left] or left
local rightExp = BRANCH_MAP[right] or right
if BRANCH_MAP[left] or BRANCH_MAP[right] then
return leftExp .. ' (' .. rightExp .. ')'
end
end
return raw
end
local function expandBranch(raw)
raw = trim(raw)
if raw == '' then
return ''
end
local parts = {}
for part in mw.text.gsplit(raw, ';', true) do
part = expandBranchToken(part)
if part ~= '' then
table.insert(parts, part)
end
end
return table.concat(parts, '; ')
end
end


Line 832: Line 716:
addHeader(tbl, 'Military service')
addHeader(tbl, 'Military service')
addRow(tbl, 'Allegiance', 'United States')
addRow(tbl, 'Allegiance', 'United States')
local branch = expandBranch(parentArg(frame, 'class_branch'))
local branch = prettyProse(parentArg(frame, 'class_branch'))
if branch == '' then
if branch == '' then
branch = 'United States Army'
branch = 'United States Army'
Line 868: Line 752:
addRow(tbl, 'IPW (German)', teamLinkList(parentArg(frame, 'ipw_ge'), 'IPW ', 'IPW'))
addRow(tbl, 'IPW (German)', teamLinkList(parentArg(frame, 'ipw_ge'), 'IPW ', 'IPW'))
addRow(tbl, 'IPW (Italian)', teamLinkList(parentArg(frame, 'ipw_it'), 'IPW Italian ', 'IPW Italian'))
addRow(tbl, 'IPW (Italian)', teamLinkList(parentArg(frame, 'ipw_it'), 'IPW Italian ', 'IPW Italian'))
addRow(tbl, 'Special', prettyProse(parentArg(frame, 'special')))
addRow(tbl, 'LOC', parentArg(frame, 'loc'))
addRow(tbl, 'LOC', parentArg(frame, 'loc'))
addRow(tbl, 'Arrived', parentArg(frame, 'date_arrive'))
addRow(tbl, 'Arrived', parentArg(frame, 'date_arrive'))
Line 917: Line 802:
end
end
return lead
return lead
end
local function researchNotesSection(content)
if not content or content == '' then
return ''
end
local startPos = mw.ustring.find(content, '== Research notes ==', 1, true)
if not startPos then
return ''
end
local after = mw.ustring.sub(content, startPos + 20)
local nextHead = mw.ustring.find(after, '\n== ', 1, true)
if nextHead then
return mw.ustring.sub(after, 1, nextHead - 1)
end
return after
end
local function noteTeamNames(text)
text = mw.ustring.upper(tostring(text or ''))
local seen = {}
local names = {}
local function add(name)
if name ~= '' and not seen[name] then
seen[name] = true
table.insert(names, name)
end
end
local work = text
for num, letter in string.gmatch(work, 'MII%s+(%d+)%s*%-%s*([A-Z])') do
add('MII ' .. num .. '-' .. letter)
end
work = string.gsub(work, 'MII%s+%d+%s*%-%s*[A-Z]', ' ')
for num in string.gmatch(work, 'MII%s+(%d+)') do
add('MII ' .. num)
end
for num, letter in string.gmatch(' ' .. text, '[^%d]([45]%d%d)%s*%-%s*([GI])') do
add('MII ' .. num .. '-' .. letter)
end
for num in string.gmatch(text, 'IPW%s+(%d+)') do
add('IPW ' .. num)
end
return names
end
function p.noteTeamCategories(frame)
local title = mw.title.getCurrentTitle()
if not title or not title.getContent then
return ''
end
local ok, content = pcall(function()
return title:getContent()
end)
if not ok or not content then
return ''
end
local bits = {}
for _, name in ipairs(noteTeamNames(researchNotesSection(content))) do
table.insert(bits, '[[Category:Team ' .. name .. ']]')
end
return table.concat(bits)
end
end


Line 991: Line 815:
return ''
return ''
end
end
local section = researchNotesSection(content)
local startPos = mw.ustring.find(content, '== Research notes ==', 1, true)
if section == '' then
if not startPos then
return ''
return ''
end
local after = mw.ustring.sub(content, startPos + 20)
local nextHead = mw.ustring.find(after, '\n== ', 1, true)
local section = after
if nextHead then
section = mw.ustring.sub(after, 1, nextHead - 1)
end
end
local items = {}
local items = {}
Line 1,019: Line 849:


return p
return p