Module:Soldier: Difference between revisions
fix_titlecase |
Remove overseas flag from soldier infobox. |
||
| Line 3: | Line 3: | ||
local function trim(s) | local function trim(s) | ||
return mw.text.trim(tostring(s or '')) | return mw.text.trim(tostring(s or '')) | ||
end | |||
local function countChar(s, ch) | |||
local _, n = mw.ustring.gsub(s, ch, '') | |||
return n | |||
end | |||
local function tidyDisplay(s) | |||
s = trim(s) | |||
if s == '' then | |||
return '' | |||
end | |||
s = mw.text.decode(s, true) | |||
s = mw.ustring.gsub(s, mw.ustring.char(160), ' ') | |||
s = mw.ustring.gsub(s, mw.ustring.char(0xFFFD), '') | |||
s = mw.ustring.gsub(s, mw.ustring.char(0x200B), '') | |||
s = trim(s) | |||
local lower = mw.ustring.lower(s) | |||
if lower == '#n/a' or lower == 'n/a' or lower == 'none' or lower == 'null' or lower == '-' then | |||
return '' | |||
end | |||
if s == '.' or s == '?' then | |||
return '' | |||
end | |||
local prev | |||
repeat | |||
prev = s | |||
s = mw.ustring.gsub(s, '""', '"') | |||
until s == prev | |||
s = trim(s) | |||
local changed = true | |||
while changed and mw.ustring.len(s) >= 2 do | |||
changed = false | |||
local first = mw.ustring.sub(s, 1, 1) | |||
local last = mw.ustring.sub(s, -1) | |||
if first == '"' and last == '"' then | |||
local inner = mw.ustring.sub(s, 2, -2) | |||
if countChar(inner, '"') == 0 then | |||
s = trim(inner) | |||
changed = true | |||
elseif countChar(s, '"') % 2 == 1 then | |||
local second = mw.ustring.find(s, '"', 2, true) | |||
local slen = mw.ustring.len(s) | |||
if second and second + 1 < slen then | |||
local nxt = mw.ustring.sub(s, second + 1, second + 1) | |||
if mw.ustring.find(nxt, '%w') then | |||
s = mw.ustring.sub(s, 2) | |||
else | |||
s = mw.ustring.sub(s, 1, -2) | |||
end | |||
else | |||
s = mw.ustring.sub(s, 1, -2) | |||
end | |||
s = trim(s) | |||
changed = true | |||
end | |||
elseif first == "'" and last == "'" then | |||
local inner = mw.ustring.sub(s, 2, -2) | |||
if not mw.ustring.find(inner, "'", 1, true) then | |||
s = trim(inner) | |||
changed = true | |||
end | |||
end | |||
end | |||
local q = countChar(s, '"') | |||
local first = mw.ustring.sub(s, 1, 1) | |||
local last = mw.ustring.sub(s, -1) | |||
if first == '"' and q == 1 and last ~= '"' then | |||
s = trim(mw.ustring.sub(s, 2)) | |||
end | |||
last = mw.ustring.sub(s, -1) | |||
first = mw.ustring.sub(s, 1, 1) | |||
q = countChar(s, '"') | |||
if last == '"' and q == 1 and first ~= '"' then | |||
s = trim(mw.ustring.sub(s, 1, -2)) | |||
end | |||
s = mw.ustring.gsub(s, '^\\+', '') | |||
s = trim(s) | |||
if s == '"' or s == "'" or s == '.' or s == '?' or s == '\\' then | |||
return '' | |||
end | |||
s = mw.ustring.gsub(s, '%s+', ' ') | |||
return trim(s) | |||
end | end | ||
local function parentArg(frame, name) | local function parentArg(frame, name) | ||
local parent = frame:getParent() | local parent = frame:getParent() | ||
local raw | |||
if parent and parent.args[name] then | if parent and parent.args[name] then | ||
return trim( | raw = parent.args[name] | ||
else | |||
raw = frame.args[name] | |||
end | |||
return tidyDisplay(raw) | |||
end | |||
local ACRONYMS = { | |||
US = true, USA = true, POW = true, IPW = true, MII = true, OSS = true, | |||
MITC = true, ASN = true, WWII = true, NARA = true, DC = true, DEML = true, | |||
CSU = true, ASTP = true, CAC = true, KIA = true, MIA = true, NG = true, | |||
MRBC = true, PACMIRS = true, GED = true, MITU = true, RDC = true, | |||
} | |||
local SMALL_WORDS = { | |||
of = true, the = true, to = true, a = true, an = true, at = true, by = true, | |||
} | |||
SMALL_WORDS['and'] = true | |||
SMALL_WORDS['for'] = true | |||
SMALL_WORDS['in'] = true | |||
SMALL_WORDS['or'] = true | |||
local STATE_NAME = { | |||
alabama = 'Alabama', alaska = 'Alaska', arizona = 'Arizona', arkansas = 'Arkansas', | |||
california = 'California', colorado = 'Colorado', connecticut = 'Connecticut', | |||
delaware = 'Delaware', florida = 'Florida', georgia = 'Georgia', hawaii = 'Hawaii', | |||
idaho = 'Idaho', illinois = 'Illinois', indiana = 'Indiana', iowa = 'Iowa', | |||
kansas = 'Kansas', kentucky = 'Kentucky', louisiana = 'Louisiana', maine = 'Maine', | |||
maryland = 'Maryland', massachusetts = 'Massachusetts', michigan = 'Michigan', | |||
minnesota = 'Minnesota', mississippi = 'Mississippi', missouri = 'Missouri', | |||
montana = 'Montana', nebraska = 'Nebraska', nevada = 'Nevada', ohio = 'Ohio', | |||
oklahoma = 'Oklahoma', oregon = 'Oregon', pennsylvania = 'Pennsylvania', | |||
tennessee = 'Tennessee', texas = 'Texas', utah = 'Utah', vermont = 'Vermont', | |||
virginia = 'Virginia', washington = 'Washington', wisconsin = 'Wisconsin', | |||
wyoming = 'Wyoming', | |||
} | |||
local STATE_ABBR = { | |||
al = 'Alabama', ak = 'Alaska', az = 'Arizona', ar = 'Arkansas', ca = 'California', | |||
co = 'Colorado', ct = 'Connecticut', de = 'Delaware', fl = 'Florida', ga = 'Georgia', | |||
hi = 'Hawaii', id = 'Idaho', il = 'Illinois', ia = 'Iowa', | |||
ks = 'Kansas', ky = 'Kentucky', la = 'Louisiana', me = 'Maine', md = 'Maryland', | |||
ma = 'Massachusetts', mi = 'Michigan', mn = 'Minnesota', ms = 'Mississippi', | |||
mo = 'Missouri', mt = 'Montana', ne = 'Nebraska', nv = 'Nevada', nh = 'New Hampshire', | |||
nj = 'New Jersey', nm = 'New Mexico', ny = 'New York', nc = 'North Carolina', | |||
nd = 'North Dakota', oh = 'Ohio', ok = 'Oklahoma', pa = 'Pennsylvania', | |||
ri = 'Rhode Island', sc = 'South Carolina', sd = 'South Dakota', tn = 'Tennessee', | |||
tx = 'Texas', ut = 'Utah', vt = 'Vermont', va = 'Virginia', wa = 'Washington', | |||
wv = 'West Virginia', wi = 'Wisconsin', wy = 'Wyoming', dc = 'Washington, D.C.', | |||
} | |||
STATE_ABBR['in'] = 'Indiana' | |||
STATE_ABBR['or'] = 'Oregon' | |||
local TWO_WORD_STATE = { | |||
['new hampshire'] = 'New Hampshire', | |||
['new jersey'] = 'New Jersey', | |||
['new mexico'] = 'New Mexico', | |||
['new york'] = 'New York', | |||
['north carolina'] = 'North Carolina', | |||
['north dakota'] = 'North Dakota', | |||
['rhode island'] = 'Rhode Island', | |||
['south carolina'] = 'South Carolina', | |||
['south dakota'] = 'South Dakota', | |||
['west virginia'] = 'West Virginia', | |||
} | |||
local PLACE_PREP = { | |||
at = true, from = true, near = true, of = true, | |||
} | |||
PLACE_PREP['in'] = true | |||
local function stateKey(w) | |||
w = mw.ustring.lower(w) | |||
w = mw.ustring.gsub(w, '[.]', '') | |||
w = mw.ustring.gsub(w, '%s+', ' ') | |||
return trim(w) | |||
end | |||
local function canonicalState(w) | |||
local k = stateKey(w) | |||
return STATE_NAME[k] or STATE_ABBR[k] or TWO_WORD_STATE[k] | |||
end | |||
local NEGATIVE_PHRASES = { | |||
'unsatisfactory', 'failed class', 'failed as', 'failure', 'flunk', | |||
'washed out', 'wash out', 'washout', 'kicked out', 'kick out', | |||
'dismissed', 'expelled', 'poor performance', 'poor work', 'poor grades', | |||
'awol', 'court-martial', 'court martial', 'disciplinary', | |||
'discharged for cause', 'dropped out', 'dropped from', 'also dropped', | |||
'physically unfit', 'unfit for', 'relieved prior', 'relieved of', | |||
'kicked', 'eliminated from', 'not graduated', 'did not graduate', | |||
} | |||
local function splitWords(s) | |||
local words = {} | |||
for w in mw.text.gsplit(s, ' ', true) do | |||
if w ~= '' then | |||
table.insert(words, w) | |||
end | |||
end | |||
return words | |||
end | |||
local function isAllCapsPhrase(s) | |||
local letters = mw.ustring.gsub(s, '[^%a]', '') | |||
if mw.ustring.len(letters) < 2 then | |||
return false | |||
end | |||
return letters == mw.ustring.upper(letters) | |||
end | |||
local function prettyTitle(s, keepSmall) | |||
s = trim(s) | |||
if s == '' then | |||
return s | |||
end | |||
local words = splitWords(s) | |||
local out = {} | |||
for i, w in ipairs(words) do | |||
local bare = mw.ustring.gsub(w, '[^%a]', '') | |||
local up = mw.ustring.upper(bare) | |||
if ACRONYMS[up] then | |||
table.insert(out, mw.ustring.gsub(w, bare, up, 1)) | |||
else | |||
local low = mw.ustring.lower(w) | |||
local lowBare = mw.ustring.lower(bare) | |||
if keepSmall and i > 1 and SMALL_WORDS[lowBare] then | |||
table.insert(out, mw.ustring.lower(w)) | |||
else | |||
local first = mw.ustring.upper(mw.ustring.sub(low, 1, 1)) | |||
table.insert(out, first .. mw.ustring.sub(low, 2)) | |||
end | |||
end | |||
end | end | ||
return | return table.concat(out, ' ') | ||
end | end | ||
local function titleCase(s) | local function titleCase(s) | ||
return prettyTitle(s, false) | |||
end | |||
local function looksLikeCode(s) | |||
s = trim(s) | |||
if s == '' then | |||
return true | |||
end | |||
if mw.ustring.find(s, '%d') and mw.ustring.len(s) <= 8 and not mw.ustring.find(s, ' ') then | |||
return true | |||
end | |||
if mw.ustring.len(s) <= 3 and not mw.ustring.find(s, ' ') then | |||
return true | |||
end | |||
return false | |||
end | |||
local function joinCityState(cityRaw, stateName, srcAllCaps) | |||
cityRaw = trim(cityRaw) | |||
if cityRaw == '' then | |||
return stateName | |||
end | |||
local words = splitWords(cityRaw) | |||
local prepIdx = nil | |||
for i, w in ipairs(words) do | |||
local k = mw.ustring.gsub(mw.ustring.lower(w), '[^%a]', '') | |||
if PLACE_PREP[k] then | |||
prepIdx = i | |||
end | |||
end | |||
local prefix = '' | |||
local city = cityRaw | |||
if prepIdx and prepIdx < #words then | |||
local preParts = {} | |||
for i = 1, prepIdx do | |||
table.insert(preParts, words[i]) | |||
end | |||
local cityParts = {} | |||
for i = prepIdx + 1, #words do | |||
table.insert(cityParts, words[i]) | |||
end | |||
prefix = table.concat(preParts, ' ') | |||
city = table.concat(cityParts, ' ') | |||
end | |||
local cityFmt = canonicalState(city) | |||
if not cityFmt then | |||
cityFmt = prettyTitle(city, false) | |||
end | |||
local place | |||
if stateName == 'Washington, D.C.' and (cityFmt == '' or mw.ustring.lower(cityFmt) == 'washington') then | |||
place = 'Washington, D.C.' | |||
else | |||
place = cityFmt .. ', ' .. stateName | |||
end | |||
if prefix ~= '' then | |||
local prefixFmt = prefix | |||
if srcAllCaps or isAllCapsPhrase(prefix) then | |||
prefixFmt = prettyTitle(prefix, true) | |||
end | |||
return prefixFmt .. ' ' .. place | |||
end | |||
return place | |||
end | |||
local function prettyPlace(s) | |||
s = trim(s) | s = trim(s) | ||
if s == '' then | if s == '' then | ||
return s | return s | ||
end | end | ||
s = mw.ustring.lower(s) | local srcAllCaps = isAllCapsPhrase(s) | ||
local compact = mw.ustring.lower(s) | |||
return | compact = mw.ustring.gsub(compact, '[.,]', '') | ||
end) | compact = mw.ustring.gsub(compact, '%s+', ' ') | ||
compact = trim(compact) | |||
if compact == 'washington dc' or compact == 'washington d c' | |||
or compact == 'district of columbia' then | |||
return 'Washington, D.C.' | |||
end | |||
if mw.ustring.find(compact, ' washington dc$') or mw.ustring.find(compact, ' washington d c$') then | |||
local city = mw.ustring.gsub(s, '[Ww][Aa][Ss][Hh][Ii][Nn][Gg][Tt][Oo][Nn]%s+[Dd]%.?%s*[Cc]%.?$', '') | |||
return joinCityState(trim(city), 'Washington, D.C.', srcAllCaps) | |||
end | |||
if mw.ustring.find(s, ',', 1, true) then | |||
local bits = {} | |||
for part in mw.text.gsplit(s, ',', true) do | |||
part = trim(part) | |||
if part ~= '' then | |||
table.insert(bits, part) | |||
end | |||
end | |||
if #bits >= 1 then | |||
local lastKey = stateKey(bits[#bits]) | |||
if lastKey == 'dc' or lastKey == 'd c' then | |||
local city = '' | |||
if #bits >= 2 then | |||
city = table.concat(bits, ', ', 1, #bits - 1) | |||
end | |||
return joinCityState(city, 'Washington, D.C.', srcAllCaps) | |||
end | |||
end | |||
local out = {} | |||
for _, part in ipairs(bits) do | |||
table.insert(out, canonicalState(part) or prettyTitle(part, false)) | |||
end | |||
return table.concat(out, ', ') | |||
end | |||
local words = splitWords(s) | |||
if #words >= 2 then | |||
local last2 = stateKey(words[#words - 1] .. ' ' .. words[#words]) | |||
if TWO_WORD_STATE[last2] then | |||
local city = {} | |||
for i = 1, #words - 2 do | |||
table.insert(city, words[i]) | |||
end | |||
return joinCityState(table.concat(city, ' '), TWO_WORD_STATE[last2], srcAllCaps) | |||
end | |||
end | |||
if #words >= 1 then | |||
local lastKey = stateKey(words[#words]) | |||
local state = STATE_NAME[lastKey] or STATE_ABBR[lastKey] | |||
if state then | |||
if #words >= 2 then | |||
local city = {} | |||
for i = 1, #words - 1 do | |||
table.insert(city, words[i]) | |||
end | |||
return joinCityState(table.concat(city, ' '), state, srcAllCaps) | |||
end | |||
return state | |||
end | |||
end | |||
if srcAllCaps then | |||
return prettyTitle(s, false) | |||
end | |||
return s | |||
end | |||
local function prettyProse(s) | |||
s = trim(s) | |||
if s == '' or looksLikeCode(s) then | |||
return s | |||
end | |||
if isAllCapsPhrase(s) or prettyPlace(s) ~= s then | |||
local placed = prettyPlace(s) | |||
if placed ~= s then | |||
return placed | |||
end | |||
end | |||
if isAllCapsPhrase(s) then | |||
return prettyTitle(s, true) | |||
end | |||
return s | |||
end | |||
local function prettyNamePart(s) | |||
s = trim(s) | |||
if s == '' then | |||
return s | |||
end | |||
if isAllCapsPhrase(s) then | |||
return prettyTitle(s, false) | |||
end | |||
return s | return s | ||
end | |||
local function isNegativeClause(s) | |||
local lower = mw.ustring.lower(s) | |||
if lower == 'failed' or mw.ustring.find(lower, '^failed%s') or mw.ustring.find(lower, '%sfailed%s') or mw.ustring.find(lower, '%sfailed$') then | |||
return true | |||
end | |||
for _, phrase in ipairs(NEGATIVE_PHRASES) do | |||
if mw.ustring.find(lower, phrase, 1, true) then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
local function sanitizeNote(s) | |||
s = tidyDisplay(s) | |||
if s == '' then | |||
return '' | |||
end | |||
local lower = mw.ustring.lower(s) | |||
if mw.ustring.find(lower, 'no notes were in the source', 1, true) then | |||
return '' | |||
end | |||
local kept = {} | |||
for clause in mw.text.gsplit(s, ';', true) do | |||
clause = trim(clause) | |||
if clause ~= '' then | |||
for sent in mw.text.gsplit(clause, '. ', true) do | |||
sent = trim(sent) | |||
sent = mw.ustring.gsub(sent, '%.$', '') | |||
if sent ~= '' and not isNegativeClause(sent) then | |||
table.insert(kept, prettyProse(sent)) | |||
end | |||
end | |||
end | |||
end | |||
return table.concat(kept, '; ') | |||
end | end | ||
| Line 30: | Line 440: | ||
local function displayName(frame) | local function displayName(frame) | ||
local first = parentArg(frame, 'first') | local first = prettyNamePart(parentArg(frame, 'first')) | ||
local middle = parentArg(frame, 'middle') | local middle = prettyNamePart(parentArg(frame, 'middle')) | ||
local surname = parentArg(frame, 'surname') | local surname = prettyNamePart(parentArg(frame, 'surname')) | ||
local suffix = parentArg(frame, 'suffix') | local suffix = prettyNamePart(parentArg(frame, 'suffix')) | ||
local parts = {} | local parts = {} | ||
if first ~= '' then | if first ~= '' then | ||
| Line 71: | Line 481: | ||
end | end | ||
return out | return out | ||
end | |||
local function teamLinkList(raw, pagePrefix, label) | |||
local out = {} | |||
for part in mw.text.gsplit(raw, ';', true) do | |||
part = trim(part) | |||
part = mw.ustring.gsub(part, '[#<>%[%]|{}]', '') | |||
part = trim(part) | |||
if part ~= '' then | |||
table.insert(out, string.format('[[Team %s%s|%s %s]]', pagePrefix, part, label, part)) | |||
end | |||
end | |||
return table.concat(out, ', ') | |||
end | |||
local function assignmentLink(raw) | |||
raw = trim(raw) | |||
if raw == '' then | |||
return '' | |||
end | |||
raw = mw.ustring.gsub(raw, '[#<>%[%]|{}]', '') | |||
raw = trim(raw) | |||
if raw == '' then | |||
return '' | |||
end | |||
return string.format('[[Assignment %s|%s]]', raw, raw) | |||
end | end | ||
| Line 91: | Line 527: | ||
end | end | ||
td:wikitext(value) | td:wikitext(value) | ||
end | |||
local function yearOnly(s) | |||
s = trim(s) | |||
if s == '' or s == '?' then | |||
return '' | |||
end | |||
local year = mw.ustring.match(s, '(%d%d%d%d)') | |||
if year then | |||
return year | |||
end | |||
return '' | |||
end | |||
local RANK_MAP = { | |||
['PVT'] = 'Private', | |||
['PVTE'] = 'Private', | |||
['PRIVATE'] = 'Private', | |||
['PFC'] = 'Private First Class', | |||
['P F C'] = 'Private First Class', | |||
['PRIVATE FIRST CLASS'] = 'Private First Class', | |||
['CPL'] = 'Corporal', | |||
['CORPORAL'] = 'Corporal', | |||
['T/5'] = 'Technician Fifth Grade', | |||
['TEC5'] = 'Technician Fifth Grade', | |||
['TEC 5'] = 'Technician Fifth Grade', | |||
['T5'] = 'Technician Fifth Grade', | |||
['TECH 5'] = 'Technician Fifth Grade', | |||
['SGT'] = 'Sergeant', | |||
['SERGEANT'] = 'Sergeant', | |||
['T/4'] = 'Technician Fourth Grade', | |||
['TEC4'] = 'Technician Fourth Grade', | |||
['TEC 4'] = 'Technician Fourth Grade', | |||
['T4'] = 'Technician Fourth Grade', | |||
['TECH 4'] = 'Technician Fourth Grade', | |||
['S/SGT'] = 'Staff Sergeant', | |||
['SSGT'] = 'Staff Sergeant', | |||
['S SGT'] = 'Staff Sergeant', | |||
['STAFF SERGEANT'] = 'Staff Sergeant', | |||
['T/3'] = 'Technician Third Grade', | |||
['TEC3'] = 'Technician Third Grade', | |||
['TEC 3'] = 'Technician Third Grade', | |||
['T3'] = 'Technician Third Grade', | |||
['TECH 3'] = 'Technician Third Grade', | |||
['T/SGT'] = 'Technical Sergeant', | |||
['TSGT'] = 'Technical Sergeant', | |||
['T SGT'] = 'Technical Sergeant', | |||
['TECHNICAL SERGEANT'] = 'Technical Sergeant', | |||
['1ST SGT'] = 'First Sergeant', | |||
['1SGT'] = 'First Sergeant', | |||
['FIRST SERGEANT'] = 'First Sergeant', | |||
['M/SGT'] = 'Master Sergeant', | |||
['MSGT'] = 'Master Sergeant', | |||
['MASTER SERGEANT'] = 'Master Sergeant', | |||
['WO'] = 'Warrant Officer', | |||
['WOJG'] = 'Warrant Officer', | |||
['WARRANT OFFICER'] = 'Warrant Officer', | |||
['CWO'] = 'Chief Warrant Officer', | |||
['2ND LT'] = 'Second Lieutenant', | |||
['2D LT'] = 'Second Lieutenant', | |||
['2LT'] = 'Second Lieutenant', | |||
['SECOND LIEUTENANT'] = 'Second Lieutenant', | |||
['1ST LT'] = 'First Lieutenant', | |||
['1LT'] = 'First Lieutenant', | |||
['FIRST LIEUTENANT'] = 'First Lieutenant', | |||
['LT'] = 'Lieutenant', | |||
['LIEUTENANT'] = 'Lieutenant', | |||
['CAPT'] = 'Captain', | |||
['CPT'] = 'Captain', | |||
['CAPTAIN'] = 'Captain', | |||
['MAJ'] = 'Major', | |||
['MAJOR'] = 'Major', | |||
['LT COL'] = 'Lieutenant Colonel', | |||
['LTCOL'] = 'Lieutenant Colonel', | |||
['LTC'] = 'Lieutenant Colonel', | |||
['LIEUTENANT COLONEL'] = 'Lieutenant Colonel', | |||
['COL'] = 'Colonel', | |||
['COLONEL'] = 'Colonel', | |||
['BRIG GEN'] = 'Brigadier General', | |||
['BG'] = 'Brigadier General', | |||
['BRIGADIER GENERAL'] = 'Brigadier General', | |||
['MAJ GEN'] = 'Major General', | |||
['MG'] = 'Major General', | |||
['MAJOR GENERAL'] = 'Major General', | |||
['LT GEN'] = 'Lieutenant General', | |||
['LIEUTENANT GENERAL'] = 'Lieutenant General', | |||
['GEN'] = 'General', | |||
['GENERAL'] = 'General', | |||
['TECH'] = 'Technician', | |||
['TEC'] = 'Technician', | |||
} | |||
local function expandRank(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) | |||
return RANK_MAP[key] or raw | |||
end | |||
local function lifespan(birth, death) | |||
birth = yearOnly(birth) | |||
death = yearOnly(death) | |||
if birth ~= '' and death ~= '' then | |||
return ' (' .. birth .. '–' .. death .. ')' | |||
end | |||
if birth ~= '' then | |||
return ' (born ' .. birth .. ')' | |||
end | |||
if death ~= '' then | |||
return ' (died ' .. death .. ')' | |||
end | |||
return '' | |||
end | |||
local function preferredRank(frame) | |||
local rank = expandRank(parentArg(frame, 'rank_final')) | |||
if rank == '' then | |||
rank = expandRank(parentArg(frame, 'class_rank')) | |||
end | |||
return rank | |||
end | end | ||
| Line 131: | Line 692: | ||
end | end | ||
local alias = parentArg(frame, 'alias') | local alias = prettyNamePart(parentArg(frame, 'alias')) | ||
local birth = parentArg(frame, 'birth_year') | local birth = yearOnly(parentArg(frame, 'birth_year')) | ||
local death = parentArg(frame, 'death_year') | local death = yearOnly(parentArg(frame, 'death_year')) | ||
local nativity = parentArg(frame, 'nativity') | local nativity = prettyPlace(parentArg(frame, 'nativity')) | ||
local religion = parentArg(frame, 'religion') | local religion = prettyProse(parentArg(frame, 'religion')) | ||
local marital = parentArg(frame, 'marital') | local marital = prettyProse(parentArg(frame, 'marital')) | ||
local education = parentArg(frame, 'education') | local education = prettyProse(parentArg(frame, 'education')) | ||
local occupation = parentArg(frame, 'occupation') | local occupation = prettyProse(parentArg(frame, 'occupation')) | ||
local state = parentArg(frame, 'state') | local state = prettyPlace(parentArg(frame, 'state')) | ||
if alias ~= '' or birth ~= '' or death ~= '' or nativity ~= '' | if alias ~= '' or birth ~= '' or death ~= '' or nativity ~= '' | ||
| Line 148: | Line 709: | ||
addRow(tbl, 'Nickname', alias, 'nickname') | addRow(tbl, 'Nickname', alias, 'nickname') | ||
addRow(tbl, 'Born', birth) | |||
addRow(tbl, 'Nativity', nativity) | |||
addRow(tbl, 'Died', death) | addRow(tbl, 'Died', death) | ||
addRow(tbl, 'Religion', religion) | addRow(tbl, 'Religion', religion) | ||
| Line 164: | Line 717: | ||
addRow(tbl, 'Occupation', occupation) | addRow(tbl, 'Occupation', occupation) | ||
if state ~= '' then | if state ~= '' then | ||
addRow(tbl, 'State', | addRow(tbl, 'State', state) | ||
end | end | ||
addHeader(tbl, 'Military service') | addHeader(tbl, 'Military service') | ||
addRow(tbl, 'Allegiance', 'United States') | addRow(tbl, 'Allegiance', 'United States') | ||
local branch = 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 176: | Line 729: | ||
addRow(tbl, 'ASN', parentArg(frame, 'asn'), 'serial') | addRow(tbl, 'ASN', parentArg(frame, 'asn'), 'serial') | ||
local rankFinal = parentArg(frame, 'rank_final') | local rankFinal = expandRank(parentArg(frame, 'rank_final')) | ||
local classRank = parentArg(frame, 'class_rank') | local classRank = expandRank(parentArg(frame, 'class_rank')) | ||
if rankFinal ~= '' and classRank ~= '' and classRank ~= rankFinal then | |||
addRow(tbl, 'Rank', rankFinal) | |||
addRow(tbl, 'Rank at Ritchie', classRank) | |||
else | |||
rank = rankFinal | local rank = rankFinal | ||
if rank == '' then | |||
rank = classRank | |||
end | |||
addRow(tbl, 'Rank', rank) | |||
end | end | ||
local classRaw = parentArg(frame, 'class_number') | local classRaw = parentArg(frame, 'class_number') | ||
local classBits = classLinkList(classRaw, false) | local classBits = classLinkList(classRaw, false) | ||
if #classBits > 0 then | if #classBits > 0 then | ||
addRow(tbl, 'Camp Ritchie', 'Class ' .. table.concat(classBits, ', ')) | |||
end | end | ||
addRow(tbl, 'Section', parentArg(frame, 'class_section')) | |||
addRow(tbl, 'Other class', parentArg(frame, 'other_class')) | |||
local enlist = parentArg(frame, 'enlistment_place') | local enlist = prettyPlace(parentArg(frame, 'enlistment_place')) | ||
if enlist ~= '' then | if enlist ~= '' then | ||
addRow(tbl, 'Enlisted', | addRow(tbl, 'Enlisted', enlist) | ||
end | end | ||
addRow(tbl, 'Assignment', parentArg(frame, 'assignment')) | addRow(tbl, 'Assignment', assignmentLink(parentArg(frame, 'assignment'))) | ||
addRow(tbl, 'Unit / division', parentArg(frame, 'division')) | addRow(tbl, 'Unit / division', prettyProse(parentArg(frame, 'division'))) | ||
addRow(tbl, 'IPW (German)', parentArg(frame, 'ipw_ge')) | addRow(tbl, 'IPW (German)', teamLinkList(parentArg(frame, 'ipw_ge'), 'IPW ', 'IPW')) | ||
addRow(tbl, 'IPW (Italian)', parentArg(frame, 'ipw_it') | addRow(tbl, 'IPW (Italian)', teamLinkList(parentArg(frame, 'ipw_it'), 'IPW Italian ', 'IPW Italian')) | ||
addRow(tbl, 'Special', prettyProse(parentArg(frame, 'special'))) | |||
addRow(tbl, 'Special', parentArg(frame, 'special')) | |||
addRow(tbl, 'LOC', parentArg(frame, 'loc')) | addRow(tbl, 'LOC', parentArg(frame, 'loc')) | ||
addRow(tbl, 'Arrived', parentArg(frame, 'date_arrive')) | |||
addRow(tbl, 'Departed', parentArg(frame, 'date_depart')) | |||
addRow(tbl, 'Certificate', parentArg(frame, 'certificate')) | addRow(tbl, 'Certificate', parentArg(frame, 'certificate')) | ||
| Line 232: | Line 769: | ||
function p.lead(frame) | function p.lead(frame) | ||
local name = displayName(frame) | local name = displayName(frame) | ||
local | local rank = preferredRank(frame) | ||
local role = 'United States Army soldier' | |||
if rank ~= '' then | |||
role = 'United States Army ' .. rank | |||
local | |||
if | |||
end | end | ||
| Line 251: | Line 779: | ||
if #classLinks == 1 then | if #classLinks == 1 then | ||
trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] | trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] | ||
elseif #classLinks > | elseif #classLinks == 2 then | ||
trained = ' who trained at [[Camp Ritchie]], Maryland, in | trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] .. ' and ' .. classLinks[2] | ||
elseif #classLinks > 2 then | |||
trained = ' who trained at [[Camp Ritchie]], Maryland, in ' | |||
.. table.concat(classLinks, ', ', 1, #classLinks - 1) | |||
.. ', and ' .. classLinks[#classLinks] | |||
else | else | ||
trained = ' associated with Camp Ritchie, Maryland' | trained = ' associated with Camp Ritchie, Maryland' | ||
end | end | ||
local | local lead = string.format( | ||
"'''%s'''%s was a | "'''%s'''%s was a %s%s.", | ||
name, | name, | ||
lifespan(parentArg(frame, 'birth_year'), parentArg(frame, 'death_year')), | |||
role, | |||
trained | trained | ||
) | ) | ||
local who = prettyNamePart(parentArg(frame, 'first')) | |||
local | if who == '' then | ||
who = prettyNamePart(parentArg(frame, 'surname')) | |||
local | end | ||
if who == '' then | |||
who = 'He' | |||
end | |||
local enlist = prettyPlace(parentArg(frame, 'enlistment_place')) | |||
if enlist ~= '' then | if enlist ~= '' then | ||
lead = lead .. ' ' .. who .. ' enlisted at ' .. enlist .. '.' | |||
end | end | ||
return lead | |||
end | |||
local | function p.researchNotes(frame) | ||
if | local title = mw.title.getCurrentTitle() | ||
if not title or not title.getContent then | |||
return '' | |||
end | end | ||
if | local ok, content = pcall(function() | ||
return title:getContent() | |||
end) | |||
if not ok or not content or content == '' then | |||
return '' | |||
end | end | ||
local startPos = mw.ustring.find(content, '== Research notes ==', 1, true) | |||
local | if not startPos then | ||
if | return '' | ||
end | end | ||
local after = mw.ustring.sub(content, startPos + 20) | |||
local | local nextHead = mw.ustring.find(after, '\n== ', 1, true) | ||
local | local section = after | ||
local | if nextHead then | ||
if | section = mw.ustring.sub(after, 1, nextHead - 1) | ||
end | end | ||
if | local items = {} | ||
for line in mw.text.gsplit(section, '\n', true) do | |||
line = trim(line) | |||
if mw.ustring.sub(line, 1, 2) == '* ' then | |||
local note = sanitizeNote(mw.ustring.sub(line, 3)) | |||
if note ~= '' then | |||
table.insert(items, note) | |||
end | |||
end | |||
end | end | ||
if # | if #items == 0 then | ||
return '' | |||
end | end | ||
local wrap = mw.html.create('div') | |||
wrap:addClass('soldier-research-notes') | |||
wrap:tag('div'):addClass('soldier-research-notes-heading'):wikitext('Research notes') | |||
local ul = wrap:tag('ul') | |||
for _, note in ipairs(items) do | |||
ul:tag('li'):wikitext(note) | |||
end | end | ||
return | return tostring(wrap) | ||
end | end | ||
return p | return p | ||