Module:Peter Bowman/ortografieBE

From Wikipedia

Documentation for this module may be created at Module:Peter Bowman/ortografieBE/doc

local p = {}

local insert = table.insert
local lower  = mw.ustring.lower

local errCategory = '[[:Kategoria:test]]'

local errStrings = {
	unrecognizedChar = 'Nierozpoznany znak $1',
	conversionError  = 'Błąd w konwersji znaku $1'
}

-- [[w:pl:Łacinka białoruska]]
local equiv = {
	vowels = {
		-- { na początku wyrazu/po samogłosce, po spółgłosce/po "ь", po apostrofie, po "л" }
		['а'] = { 'a',  'a',  nil,  'a' }, ['А'] = { 'A',  'A',  nil,  'a' },
		['э'] = { 'e',  'e',  nil,  'e' }, ['Э'] = { 'E',  'E',  nil,  'e' },
		['і'] = { 'i',  'i',  'ji', 'i' }, ['І'] = { 'I',  'I',  'Ji', 'i' },
		['о'] = { 'o',  'o',  nil,  'o' }, ['О'] = { 'O',  'O',  nil,  'o' },
		['у'] = { 'u',  'u',  nil,  'u' }, ['У'] = { 'U',  'U',  nil,  'u' },
		['ы'] = { nil,  'y',  nil,  'y' }, ['Ы'] = { nil,  'Y',  nil,  'y' },
		['я'] = { 'ja', 'ia', 'ja', 'a' }, ['Я'] = { 'Ja', 'Ia', 'Ja', 'a' },
		['е'] = { 'je', 'ie', 'je', 'e' }, ['Е'] = { 'Je', 'Ie', 'Je', 'e' },
		['ё'] = { 'jo', 'io', 'jo', 'o' }, ['Ё'] = { 'Jo', 'Io', 'Jo', 'o' },
		['ю'] = { 'ju', 'iu', 'ju', 'u' }, ['Ю'] = { 'Ju', 'Iu', 'Ju', 'u' }
	},
	consonants = {
		-- { normalnie, przed "ь"/przed "я", "е", "ё", "ю", "ь" }
		['б'] = { 'b',  'b' },  ['Б'] = { 'B',  'B' },
		['в'] = { 'v',  'v' },  ['В'] = { 'V',  'V' },
		['г'] = { 'h',  'h' },  ['Г'] = { 'H',  'H' },
		['д'] = { 'd',  nil },  ['Д'] = { 'D',  nil },
		['ж'] = { 'ž',  nil },  ['Ж'] = { 'Ž',  nil },
		['з'] = { 'z',  'ź' },  ['З'] = { 'Z',  'Ź' },
		['й'] = { 'j',  'j' },  ['Й'] = { 'J',  'J' },
		['к'] = { 'k',  'k' },  ['К'] = { 'K',  'K' },
		['л'] = { 'ł',  'l' },  ['Л'] = { 'Ł',  'L' },
		['м'] = { 'm',  'm' },  ['М'] = { 'M',  'M' },
		['н'] = { 'n',  'ń' },  ['Н'] = { 'N',  'Ń' },
		['п'] = { 'p',  'p' },  ['П'] = { 'P',  'P' },
		['р'] = { 'r',  nil },  ['Р'] = { 'r',  nil },
		['с'] = { 's',  'ś' },  ['С'] = { 's',  'Ś' },
		['т'] = { 't',  nil },  ['Т'] = { 'T',  nil },
		['ў'] = { 'ŭ',  'ŭ' },  ['Ў'] = { 'Ŭ',  'Ŭ' },
		['ф'] = { 'f',  'f' },  ['Ф'] = { 'F',  'F' },
		['х'] = { 'ch', 'ch' }, ['Х'] = { 'Ch', 'Ch' },
		['ц'] = { 'c',  'ć' },  ['Ц'] = { 'C',  'Ć' },
		['ч'] = { 'č',  nil },  ['Ч'] = { 'Č',  nil },
		['ш'] = { 'š',  nil },  ['Ш'] = { 'Š',  nil },
		['ь'] = { '',   nil },
		["'"] = { '',   nil }
	},
	common = {
		[' '] = true,
		['.'] = true,
		[','] = true,
		['–'] = true,
		['—'] = true
	}
}

local Romanizator = {
	output = {},
	chars  = {},
	currentPos = nil
}

function Romanizator:addChar( char )
	local lc = lower( char )
	
	if equiv.vowels[ char ] then
		insert( self.chars, {
			value   = char,
			type    = 'vowel',
			special = ( lc == 'я' or lc == 'е' or lc == 'ё' or lc == 'ю' or lc == 'і' ),
			conversion = equiv.vowels[ char ]
		} )
	elseif equiv.consonants[ char ] then
		insert( self.chars, {
			value = char,
			type  = 'consonant',
			special = ( lc == 'з' or lc == 'н' or lc == 'с' or lc == 'ц' ),
			conversion = equiv.consonants[ char ]
		} )
	elseif equiv.common[ char ] then
		insert( self.chars, {
			value = char,
			type  = 'common'
		} )
	else
		return false
	end
	
	return true
end

function Romanizator:saveLatinChar( char, conversion )
	if not conversion then
		self.error = self.error or char
	else
		insert( self.output, conversion )
	end
end

function Romanizator:checkVowel( char )
	local prevPos = self.currentPos - 1
	
	if
		self.currentPos == 1 or
		self.chars[ prevPos ].type == 'vowel'
	then
		self:saveLatinChar( char, char.conversion[ 1 ] )
	elseif
		lower( self.chars[ prevPos ].value ) == 'л'
	then
		self:saveLatinChar( char, char.conversion[ 4 ] )
	elseif
		self.chars[ prevPos ].value == 'ь' or
		self.chars[ prevPos ].value == '\''
	then
		self:saveLatinChar( char, char.conversion[ 3 ] )
	else
		self:saveLatinChar( char, char.conversion[ 2 ] )
	end
end

function Romanizator:checkConsonant( char )
	local nextChar = self.chars[ self.currentPos + 1 ]
	
	if
		nextChar.value == 'ь' or
		( not char.special and nextChar.type == 'vowel' and nextChar.special )
	then
		self:saveLatinChar( char, char.conversion[ 2 ] )
	else
		self:saveLatinChar( char, char.conversion[ 1 ] )
	end
end

function Romanizator:romanize()
	for i, char in ipairs( self.chars ) do
		self.currentPos = i
		
		if char.type == 'vowel' then
			self:checkVowel( char )
		elseif char.type == 'consonant' then
			self:checkConsonant( char )
		elseif char.type == 'common' then
			insert( self.output, char.value )
		end
	end
	
	if self.error then
		return (
			string.gsub( errStrings.conversionError, '$1', self.error )
		) .. errCategory
	else
		return table.concat( self.output, '' )
	end
end

function Romanizator:create( o )
	o = o or {}
	setmetatable( o, self )
	self.__index = self
	return o
end

p.main = function( frame )
	local args = frame.args
	local pargs = frame:getParent().args
	
	local lacinka = Romanizator:create()
	
	for codepoint in mw.ustring.gcodepoint( args[ 1 ] ) do
		if not lacinka:addChar( mw.ustring.char( codepoint ) ) then
			return ( string.gsub(
				errStrings.unrecognizedChar, '$1', mw.ustring.char( codepoint )
			) ) .. errCategory
		end
	end
	
	return lacinka:romanize()
end

return p