Genshin Impact Wiki
Genshin Impact Wiki
Documentation icon Module documentation

This module implements {{Ja-rm}}.

local p = {}

local mapping = {
	['ア']='Qa',  ['イ']='Qi',  ['ウ']='Qu',  ['エ']='Qe',  ['オ']='Qo',
	                            ['ヴ']='vu',
	['カ']='ka',  ['キ']='ki',  ['ク']='ku',  ['ケ']='ke',  ['コ']='ko',
	['ガ']='ga',  ['ギ']='gi',  ['グ']='gu',  ['ゲ']='ge',  ['ゴ']='go',
	['サ']='sa',  ['シ']='Si',  ['ス']='su',  ['セ']='se',  ['ソ']='so',        --Si = shi
	['ザ']='za',  ['ジ']='ji',  ['ズ']='zu',  ['ゼ']='ze',  ['ゾ']='zo',
	['タ']='ta',  ['チ']='Ci',  ['ツ']='Tu',  ['テ']='te',  ['ト']='to',        --Ci = chi; Tu = tsu
	['ダ']='da',  ['ヂ']='Ji',  ['ヅ']='Zu',  ['デ']='de',  ['ド']='do',        --Ji = dji; Zu = dzu
	['ナ']='na',  ['ニ']='ni',  ['ヌ']='nu',  ['ネ']='ne',  ['ノ']='no',
	['ハ']='ha',  ['ヒ']='hi',  ['フ']='fu',  ['ヘ']='he',  ['ホ']='ho',
	['バ']='ba',  ['ビ']='bi',  ['ブ']='bu',  ['ベ']='be',  ['ボ']='bo',
	['パ']='pa',  ['ピ']='pi',  ['プ']='pu',  ['ペ']='pe',  ['ポ']='po',
	['マ']='ma',  ['ミ']='mi',  ['ム']='mu',  ['メ']='me',  ['モ']='mo',
	['ヤ']='QA',                ['ユ']='QU',                ['ヨ']='QO',        --A = ya; U = yu; O = yo
	['ラ']='ra',  ['リ']='ri',  ['ル']='ru',  ['レ']='re',  ['ロ']='ro',
	['ワ']='wa',  ['ヰ']='wi',                ['ヱ']='we',  ['ヲ']='wo',
	['ヷ']='va',  ['ヸ']='vi',                ['ヹ']='ve',  ['ヺ']='vo',
	['ン']='nQ',
	['ャ']='~A',                ['ュ']='~U',                ['ョ']='~O',        --A = ya; U = yu; O = yo
	['ァ']='~a',  ['ィ']='~i',  ['ゥ']='~u',  ['ェ']='~e',  ['ォ']='~o',
	['ヮ']='~wa',
	['ー']='{-}', ['ッ']="{'}", ['・']='·',   ['゠']='·'
}

local mapping2 = {
	['スィ']='si',  ['ズィ']='zi',
	['ティ']='ti',  ['ディ']='di',
	['トゥ']='tu',  ['ドゥ']='du',
	['ホゥ']='hu'
}

local shorthand = {
	['S'] = 'sh',
	['C'] = 'ch',  ['T'] = 'ts',
	['J'] = 'dj',  ['Z'] = 'dz',
	['A'] = 'ya',  ['U'] = 'yu',  ['O'] = 'yo'
}

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		parentFirst = true,
		wrappers = {'Template:Ja-rm'}
	})
	if (not args[1]) then return '' end
	
	return p._main(args)
end

function p._main(args)
	local str = require('Module:tt').CleanTT(mw.text.unstrip(args[1]))
	if (not str or str:gsub('%s*', '') == '') then return '' end
	
	local check = str
	check = mw.ustring.gsub(check, '[゠-ー·]', '')                              --if string contains symbols other than [゠-ー·] then don't romanize
	if check ~= '' then return '' end
	local unexpected = 0
	
	str = mw.ustring.gsub(str, '~', '{tilde}')
	str = mw.ustring.gsub(str, 'ッ+', 'ッ')                                     --*reduce repeated sokuon to one
	str = mw.ustring.gsub(str, 'ー+', 'ー')                                     --*reduce repeated chouonpu to one
	str = mw.ustring.gsub(str, '.[ィゥ]', mapping2)                             --mapping2 before mapping
	str = mw.ustring.gsub(str, '.', mapping)
	str = str
		:gsub('([vkgsSzjtCTdJZnhfbpmyrw])([aiueo])~%2{%-}', '%1%2~%2')			--exception: anything + same small vowel + chouonpu
		:gsub('Q([aeo])~%1{%-}', 'Q%1~%1')										--cont'd: except for yii, wii
		:gsub('A~a{%-}', 'Aa'):gsub('U~u{%-}', 'Uu'):gsub('O~o{%-}', 'Oo')		--cont'd
		
		:gsub('([fTZ])u~([aieoAUO])', '%1%2')									--fu/tsu/dzu + small a/i/e/o/ya/yu/yo
		:gsub('Qi~([aiueo])', 'y%1')											--i + small a/i/u/e/o
		:gsub('Qu~([aiueoAUO])', 'w%1')											--u + small a/i/u/e/o/ya/yu/yo
		:gsub('vu~([aiueoAUO])', 'v%1')											--vu + small a/i/u/e/o/ya/yu/yo
		:gsub('([SjCJ])i~([eAUO])', '%1_%2')									--shi/chi/ji/dji + small e/ya/yu/yo (mark with _ to change A/U/O [ya/yu/yo] to a/u/o)
		:gsub('_.', mw.ustring.lower):gsub('_', '')
		:gsub('([vkgsztTdZnhfbpmyrw])i~([AUO])', '%1%2')						--all other i + small ya/yu/yo
		:gsub('([vkgsztTdZnhfbpmyrw])i~e', '%1ye')								--all other i + small e
		:gsub('([td])e~([AUO])', '%1%2')										--te/de + small ya/yu/yo
		:gsub('([vkgszTZnfbpmyr])u~([aiueo])', '%1w%2')							--most u + small a/i/u/e/o (fu/tsu/dzu/vu + small u)
		:gsub('U~([aiueo])', 'yw%1')											--yu + small a/i/u/e/o
		:gsub('([tdh])o~([aieo])', '%1w%2')										--to/do/ho + small a/i/e/o
		:gsub('([vkgszTZnfbpmyr])u~wa', '%1wa')									--most u + small wa
		:gsub('U~wa', 'ywa')													--yu + small wa
		:gsub('([tdh])o~wa', '%1wa')											--to/do/ho + small wa
	
		:gsub('.', shorthand)
		:gsub('([aeo])~%1', '%1%1')												--any a + small a; e + small e; o + small o
		:gsub('%~', function() unexpected = 1 end, 1)							--categorization
		:gsub('([aiueo]){%-}', '%1%1')											--chouonpu
		:gsub("{'}Q?([vkgszjtcdnhfbpmyrw])", '%1%1')							--sokuon (geminate consonant)
		:gsub("{'}", "'")														--sokuon (glottal stop)
		:gsub('·', ' ')
		:gsub('nQ(Qy?[aiueo])', "nQ'%1")										--add apostrophe between ン and following vowel
		:gsub('[~Q]', '')														--remove symbols used in romanization
		:gsub('{%-}', '')														--remove any unconverted chouonpu
		:gsub('{tilde}', '~')
		:gsub('%f[%a].', mw.ustring.upper)										--capitalize all words
		:gsub("%f[%A]'.", mw.ustring.lower)										--decapitalize all letters after mid-word apostrophes
	
	if (unexpected == 1 and args.errorcat) then str = str .. '[[Category:Ja-rm With Unexpected Input]]' end

    return str
end

return p