Module:Soldier: Difference between revisions
Import soldier lead module |
Import soldier lead module |
||
| Line 99: | Line 99: | ||
end | end | ||
return tidyDisplay(raw) | 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 = { | |||
and = true, of = true, the = true, for = true, to = true, in = true, | |||
a = true, an = true, at = true, by = true, 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', ['in'] = 'Indiana', 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', ['or'] = 'Oregon', 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.', | |||
} | |||
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 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 | |||
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 prettyPlace(s) | |||
s = trim(s) | |||
if s == '' then | |||
return s | |||
end | |||
local compact = mw.ustring.lower(s) | |||
compact = mw.ustring.gsub(compact, '[.,]', '') | |||
compact = mw.ustring.gsub(compact, '%s+', ' ') | |||
compact = trim(compact) | |||
if compact == 'washington dc' or compact == 'washington d c' | |||
or compact == 'district of columbia' or compact == 'washington dc' 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]%.?$', '') | |||
city = prettyTitle(trim(city), false) | |||
if city ~= '' then | |||
return city .. ', Washington, D.C.' | |||
end | |||
return 'Washington, D.C.' | |||
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, prettyTitle(part, false)) | |||
end | |||
end | |||
return table.concat(bits, ', ') | |||
end | |||
local words = splitWords(s) | |||
if #words >= 2 then | |||
local last2 = mw.ustring.lower(words[#words - 1] .. ' ' .. words[#words]) | |||
last2 = mw.ustring.gsub(last2, '%.', '') | |||
if TWO_WORD_STATE[last2] then | |||
local city = {} | |||
for i = 1, #words - 2 do | |||
table.insert(city, words[i]) | |||
end | |||
if #city > 0 then | |||
return prettyTitle(table.concat(city, ' '), false) .. ', ' .. TWO_WORD_STATE[last2] | |||
end | |||
return TWO_WORD_STATE[last2] | |||
end | |||
end | |||
if #words >= 1 then | |||
local last = mw.ustring.lower(words[#words]) | |||
last = mw.ustring.gsub(last, '%.', '') | |||
local state = STATE_NAME[last] or STATE_ABBR[last] | |||
if state then | |||
if #words >= 2 then | |||
local city = {} | |||
for i = 1, #words - 1 do | |||
table.insert(city, words[i]) | |||
end | |||
return prettyTitle(table.concat(city, ' '), false) .. ', ' .. state | |||
end | |||
return state | |||
end | |||
end | |||
if isAllCapsPhrase(s) 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) | s = trim(s) | ||
if s == '' then | if s == '' then | ||
return s | return s | ||
end | end | ||
if isAllCapsPhrase(s) then | |||
return prettyTitle(s, false) | |||
end | |||
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 118: | Line 365: | ||
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 159: | Line 406: | ||
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 | end | ||
| Line 357: | Line 617: | ||
end | end | ||
local alias = parentArg(frame, 'alias') | local alias = prettyNamePart(parentArg(frame, 'alias')) | ||
local birth = yearOnly(parentArg(frame, 'birth_year')) | local birth = yearOnly(parentArg(frame, 'birth_year')) | ||
local death = yearOnly(parentArg(frame, 'death_year')) | local death = yearOnly(parentArg(frame, 'death_year')) | ||
local nativity = parentArg(frame, 'nativity') | local nativity = parentArg(frame, 'nativity') | ||
local religion = parentArg(frame, 'religion') | local religion = 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 382: | Line 642: | ||
addRow(tbl, 'Occupation', occupation) | addRow(tbl, 'Occupation', occupation) | ||
if state ~= '' then | if state ~= '' then | ||
addRow(tbl, 'State', | addRow(tbl, 'State', state) | ||
end | end | ||
| Line 415: | Line 675: | ||
addRow(tbl, 'Other class', parentArg(frame, 'other_class')) | 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', assignmentLink(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', parentArg(frame, 'special')) | 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 454: | Line 714: | ||
end | end | ||
local lead = string.format( | |||
"'''%s'''%s was a %s%s.", | "'''%s'''%s was a %s%s.", | ||
name, | name, | ||
| Line 461: | Line 721: | ||
trained | trained | ||
) | ) | ||
local who = prettyNamePart(parentArg(frame, 'first')) | |||
if who == '' then | |||
who = prettyNamePart(parentArg(frame, 'surname')) | |||
end | |||
if who == '' then | |||
who = 'He' | |||
end | |||
local enlist = prettyPlace(parentArg(frame, 'enlistment_place')) | |||
if enlist ~= '' then | |||
lead = lead .. ' ' .. who .. ' enlisted at ' .. enlist .. '.' | |||
end | |||
return lead | |||
end | |||
function p.researchNotes(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 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) | |||
local section = after | |||
if nextHead then | |||
section = mw.ustring.sub(after, 1, nextHead - 1) | |||
end | |||
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 | |||
if #items == 0 then | |||
return '' | |||
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 | |||
return tostring(wrap) | |||
end | end | ||
return p | return p | ||