Module:Th-rm
Appearance
| Main | Documentation | Usage |
This module implements {{th-rm}}.
local p = {}
local U = mw.ustring
local gsub = U.gsub
local match = U.match
local sub = U.sub
local len = U.len
local INITIAL = {
['ก'] = 'k',
['ข'] = 'kh', ['ฃ'] = 'kh', ['ค'] = 'kh', ['ฅ'] = 'kh', ['ฆ'] = 'kh',
['ง'] = 'ng',
['จ'] = 'ch',
['ฉ'] = 'ch', ['ช'] = 'ch',
['ซ'] = 's',
['ฌ'] = 'ch',
['ญ'] = 'y',
['ฎ'] = 'd',
['ฏ'] = 't',
['ฐ'] = 'th', ['ฑ'] = 'th', ['ฒ'] = 'th',
['ณ'] = 'n',
['ด'] = 'd',
['ต'] = 't',
['ถ'] = 'th', ['ท'] = 'th', ['ธ'] = 'th',
['น'] = 'n',
['บ'] = 'b',
['ป'] = 'p',
['ผ'] = 'ph',
['ฝ'] = 'f',
['พ'] = 'ph',
['ฟ'] = 'f',
['ภ'] = 'ph',
['ม'] = 'm',
['ย'] = 'y',
['ร'] = 'r',
['ล'] = 'l',
['ว'] = 'w',
['ศ'] = 's', ['ษ'] = 's', ['ส'] = 's',
['ห'] = 'h',
['ฬ'] = 'l',
['ฮ'] = 'h'
}
local FINAL = {
['ก'] = 'k',
['ข'] = 'k', ['ฃ'] = 'k', ['ค'] = 'k', ['ฅ'] = 'k', ['ฆ'] = 'k',
['ง'] = 'ng',
['จ'] = 't',
['ฉ'] = 't', ['ช'] = 't', ['ซ'] = 't',
['ฌ'] = '',
['ญ'] = 'n',
['ฎ'] = 't', ['ฏ'] = 't',
['ฐ'] = 't', ['ฑ'] = 't', ['ฒ'] = 't',
['ณ'] = 'n',
['ด'] = 't',
['ต'] = 't',
['ถ'] = 't', ['ท'] = 't', ['ธ'] = 't',
['น'] = 'n',
['บ'] = 'p',
['ป'] = 'p',
['ผ'] = '', ['ฝ'] = '',
['พ'] = 'p', ['ฟ'] = 'p', ['ภ'] = 'p',
['ม'] = 'm',
['ย'] = '',
['ร'] = 'n',
['ล'] = 'n',
['ว'] = '',
['ศ'] = 't', ['ษ'] = 't', ['ส'] = 't',
['ห'] = '',
['ฬ'] = 'n',
['ฮ'] = ''
}
local CONSONANTS = 'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬฮ'
local function isConsonant(c)
return c and match(c, '[' .. CONSONANTS .. ']') ~= nil
end
local function isThai(c)
return c and match(c, '[ก-๛]') ~= nil
end
local function isVowelMark(c)
return c and match(c, '[ะาิีึืุูัำเแโใไอ]') ~= nil
end
local function clean(str)
str = mw.text.unstrip(str or '')
str = gsub(str, '<br%s*/?>', ' ')
str = gsub(str, '<[^>]+>', '')
return str
end
local function removeMarks(str)
-- Tone marks are not represented in RTGS.
str = gsub(str, '[่้๊๋]', '')
-- Mai thanthakhat makes the marked consonant silent.
str = gsub(str, '([ก-ฮ])์', '')
return str
end
local function getVowel(str, pos)
local s = sub(str, pos, -1)
-- Longest / most specific patterns first.
local patterns = {
{ 'เ', 'ื', 'อ', 'ย', 'ueai' },
{ 'เ', 'ี', 'ย', 'ว', 'iao' },
{ 'เ', 'ี', 'ย', 'ะ', 'ia' },
{ 'เ', 'ี', 'ย', '', 'ia' },
{ 'เ', 'ื', 'อ', 'ะ', 'uea' },
{ 'เ', 'ื', 'อ', '', 'uea' },
{ '', 'ั', 'ว', 'ะ', 'ua' },
{ '', 'ั', 'ว', '', 'ua' },
{ 'แ', '็', 'ว', '', 'aeo' },
{ 'แ', 'ว', '', '', 'aeo' },
{ 'เ', '็', 'ว', '', 'eo' },
{ 'เ', 'ว', '', '', 'eo' },
{ '', 'ิ', 'ว', '', 'io' },
{ '', 'ุ', 'ย', '', 'ui' },
{ '', 'ว', 'ย', '', 'uai' },
{ 'เ', 'ื', 'อ', '', 'ue' },
{ 'เ', 'ื', '', '', 'ue' },
{ 'เ', 'า', '', '', 'ao' },
{ '', 'า', 'ว', '', 'ao' },
{ 'โ', 'ย', '', '', 'oi' },
{ '', 'อ', 'ย', '', 'oi' },
{ 'เ', 'ย', '', '', 'oei' },
{ 'ใ', '', '', '', 'ai' },
{ 'ไ', '', '', '', 'ai' },
{ '', 'ั', 'ย', '', 'ai' },
{ '', 'า', 'ย', '', 'ai' },
{ 'เ', 'าะ', '', '', 'o' },
{ 'โ', 'ะ', '', '', 'o' },
{ 'โ', '', '', '', 'o' },
{ '', 'อ', '', '', 'o' },
{ 'เ', 'อะ', '', '', 'oe' },
{ 'เ', 'ิ', '', '', 'oe' },
{ 'เ', 'อ', '', '', 'oe' },
{ 'แ', 'ะ', '', '', 'ae' },
{ 'แ', '', '', '', 'ae' },
{ 'เ', 'ะ', '', '', 'e' },
{ 'เ', '็', '', '', 'e' },
{ 'เ', '', '', '', 'e' },
{ '', 'ำ', '', '', 'am' },
{ '', 'ะ', '', '', 'a' },
{ '', 'ั', '', '', 'a' },
{ '', 'า', '', '', 'a' },
{ '', 'ิ', '', '', 'i' },
{ '', 'ี', '', '', 'i' },
{ '', 'ึ', '', '', 'ue' },
{ '', 'ื', '', '', 'ue' },
{ '', 'ุ', '', '', 'u' },
{ '', 'ู', '', '', 'u' }
}
for _, v in ipairs(patterns) do
local a = v[1] or ''
local b = v[2] or ''
local c = v[3] or ''
local d = v[4] or ''
local roman = v[5] or ''
local pattern = a .. b .. c .. d
if pattern ~= '' and sub(s, 1, len(pattern)) == pattern then
return roman, len(pattern)
end
end
-- Implied a.
return 'a', 0
end
local function romanizeSyllable(str, start)
local pos = start
local n = len(str)
local initial = ''
local initialRom = ''
-- Preposed vowels are written before the initial consonant.
local pre = sub(str, pos, pos)
if pre == 'เ' or pre == 'แ' or pre == 'โ' or pre == 'ใ' or pre == 'ไ' then
pos = pos + 1
end
local first = sub(str, pos, pos)
if not isConsonant(first) then
return first, 1
end
initial = first
initialRom = INITIAL[first] or ''
pos = pos + 1
-- ห + sonorant consonant: ห is not romanized.
local second = sub(str, pos, pos)
if initial == 'ห' and second and match(second, '[งนมยรลวญณฬ]') then
initial = second
initialRom = INITIAL[second]
pos = pos + 1
end
-- จร-, ซร-, ศร-, สร-: ร is not romanized.
second = sub(str, pos, pos)
if second == 'ร'
and (initial == 'จ' or initial == 'ซ' or initial == 'ศ' or initial == 'ส') then
pos = pos + 1
end
-- Read the vowel.
local vowelPos
if pre == 'เ' or pre == 'แ' or pre == 'โ' or pre == 'ใ' or pre == 'ไ' then
vowelPos = start
else
vowelPos = pos
end
local vowel, vowelLen = getVowel(str, vowelPos)
-- Advance over the vowel.
if vowelLen > 0 then
pos = vowelPos + vowelLen
end
-- If there was a preposed vowel, getVowel consumed from its position,
-- so the resulting position already includes it.
if vowelLen == 0 and (pre == 'เ' or pre == 'แ' or pre == 'โ' or pre == 'ใ' or pre == 'ไ') then
pos = start + 1
end
-- Final consonant.
local final = sub(str, pos, pos)
local finalRom = ''
if isConsonant(final) then
local after = sub(str, pos + 1, pos + 1)
-- If another vowel begins immediately afterward, this consonant
-- belongs to the following syllable.
if not isVowelMark(after) and not (after == 'เ' or after == 'แ' or after == 'โ' or after == 'ใ' or after == 'ไ') then
finalRom = FINAL[final] or ''
pos = pos + 1
-- Final -ร after another final consonant.
if final == 'ร' then
finalRom = 'n'
end
end
end
-- ทร- exception.
if initial == 'ท' and sub(str, pos, pos) == 'ร' then
initialRom = 's'
pos = pos + 1
end
-- -รร-
-- With a final consonant, รร = a.
-- Without a final consonant, รร = an.
if sub(str, vowelPos, vowelPos + 1) == 'รร' then
if finalRom ~= '' then
vowel = 'a'
else
vowel = 'an'
end
end
return initialRom .. vowel .. finalRom, math.max(1, pos - start)
end
local function romanizeWord(word)
local result = {}
local pos = 1
local n = len(word)
while pos <= n do
local c = sub(word, pos, pos)
if c == '<' then
local close = mw.ustring.find(word, '>', pos + 1, true)
if close then
local marker = sub(word, pos, close)
if marker == '< >' then
table.insert(result, ' ')
elseif marker == '<->' then
table.insert(result, '-')
else
table.insert(result, marker)
end
pos = close + 1
else
table.insert(result, c)
pos = pos + 1
end
elseif isThai(c) then
local roman, consumed = romanizeSyllable(word, pos)
table.insert(result, roman)
pos = pos + consumed
else
table.insert(result, c)
pos = pos + 1
end
end
return table.concat(result)
end
local function capitalizeWords(str)
local chars = mw.text.split(str, '')
local capitalize = true
for i, c in ipairs(chars) do
if match(c, '[A-Za-z]') then
if capitalize then
chars[i] = U.upper(c)
capitalize = false
end
elseif c == ' ' or c == '-' then
capitalize = true
end
end
return table.concat(chars)
end
local function sentenceCase(str)
local chars = mw.text.split(str, '')
local capitalize = true
for i, c in ipairs(chars) do
if match(c, '[A-Za-z]') then
if capitalize then
chars[i] = U.upper(c)
capitalize = false
end
elseif match(c, '[.!?]') then
capitalize = true
end
end
return table.concat(chars)
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
parentFirst = true,
wrappers = {'Template:Th-rm'}
})
if not args[1] or args[1] == '' then
return ''
end
local str = clean(args[1])
-- Nothing to romanize.
if not match(str, '[ก-๛]') then
return ''
end
str = removeMarks(str)
local result = romanizeWord(str)
if args.capi then
result = capitalizeWords(result)
elseif args.sent then
result = sentenceCase(result)
end
return result
end
return p