working: hanp
 ]]

local func = {}

local ustring = mw.ustring

-- Helper Function
--
Helper Function to interpret boolean strings

function getBoolean( boolean_str )
 local boolean_value;

 if type( boolean_str ) == 'string' then
 boolean_str = boolean_str:lower;
 if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
 or boolean_str == '' or boolean_str == '아니오' then
 boolean_value = false;
 else
 boolean_value = true;
 end
 elseif type( boolean_str ) == 'boolean' then
 boolean_value = boolean_str;
 else
 error( 'No boolean value found' );
 end 
 return boolean_value
end

-- data definition

local final_vowel = 1
local final_consonant = 2
local final_rieul = 3
local final_unknown = 4

local handata = {}

-- 한글 이외 글자의 읽는법 --
final_map = {
 ["ㄱ"]= final_consonant,--기역/기윽
 ["ㄴ"]= final_consonant,--니은
 ["ㄷ"]= final_consonant,--디귿/디읃
 ["ㄹ"]= final_rieul, --리을
 ["ㅁ"]= final_consonant,--미음
 ["ㅂ"]= final_consonant,--비읍
 ["ㅅ"]= final_consonant,--시옷/시읏
 ["ㅇ"]= final_consonant,--이응
 ["ㅈ"]= final_consonant,--지읒
 ["ㅊ"]= final_consonant,--치읓
 ["ㅋ"]= final_consonant,--키읔
 ["ㅌ"]= final_consonant,--티읕
 ["ㅍ"]= final_consonant,--피읖
 ["ㅎ"]= final_consonant,--히읗
 ["ㄲ"]= final_consonant,--쌍기역/된기윽
 ["ㄸ"]= final_consonant,--쌍디귿/된디읃
 ["ㅃ"]= final_consonant,--쌍비읍/된비읍
 ["ㅆ"]= final_consonant,--쌍시옷/된시읏
 ["ㅉ"]= final_consonant,--씽지읒/된지읒

 ["0"] = final_consonant,-- 영, 십, 백, 천, 만, 억 (조 이상은 에러)
 ["1"] = final_rieul, -- 일
 ["2"] = final_vowel, -- 이
 ["3"] = final_consonant,-- 삼
 ["4"] = final_vowel, -- 사
 ["5"] = final_vowel, -- 오
 ["6"] = final_consonant,-- 육
 ["7"] = final_rieul, -- 칠
 ["8"] = final_rieul, -- 팔
 ["9"] = final_vowel, -- 구

 A = final_vowel, -- 에이
 B = final_vowel, -- 비
 C = final_vowel, -- 시
 D = final_vowel, -- 디
 E = final_vowel, -- 이
 F = final_vowel, -- 에프
 G = final_vowel, -- 지
 H = final_vowel, -- 에이치
 I = final_vowel, -- 아이
 J = final_vowel, -- 제이
 K = final_vowel, -- 케이
 L = final_rieul, -- 엘
 M = final_consonant, -- 엠
 N = final_consonant, -- 엔
 O = final_vowel, -- 오
 P = final_consonant, -- 피
 Q = final_consonant, -- 큐
 R = final_vowel, -- 아르 (알?)
 S = final_vowel, -- 에스
 T = final_vowel, -- 티
 U = fianl_vowel, -- 유
 V = final_vowel, -- 브이
 W = final_vowel, -- 더블유
 X = final_vowel, -- 엑스
 Y = final_vowel, -- 와이
 Z = final_vowel, -- 지, 제드, 제트

--
 Return값
 0: 받침이 없는 경우
 1: 'ㄹ' 받침인 경우
 2: 기타 받침인 경우
 3: 처리할 수 없는 경우
 
local function finalclass(str)
 local lastchar = ustring.match(str, '.*([%w])')
 
 if lastchar == nil then return final_unknown end

 if lastchar >= '가' and lastchar <= '힣' then
 codepoint = ustring.codepoint(lastchar)
 final = (codepoint - 0xAC00) % 0x1C
 if final == 0 then
 return final_vowel
 elseif final == 8 then
 return final_rieul
 else
 return final_consonant
 end
 end

 return final_map[lastchar] or final_unknown
end

local particle_map = {
 -- 기본형, 배~, 감~, 귤~

finalform_basic = {}
finalform_vowel = {}
finalform_consonant = {}
finalform_rieul = {}

local function registerParticleMap(rules)
 local finalform = { {}, {}, {}, {} }
 mw.log(#rules)
 for i = 1, #rules do
 rule = rules[i]
 for j = 1, 4 do
 finalform_basic[ rule[j] ] = rule[1]
 finalform_vowel[ rule[j] ] = rule[2]
 finalform_consonant[ rule[j] ] = rule[3]
 finalform_rieul[ rule[j] ] = rule[4]
 end
 end
 
 return #rules
end

registerParticleMap(particle_map)

func.particle_map = particle_map
func.registerParticleMap = registerParticleMap
func.finalform_basic = finalform_basic
func.finalform_vowel = finalform_vowel
func.finalform_consonant =finalform_consonant
func.fonalform_rieul = finalform_rieul

--
 사용법:

 str = 체언
 josa = 조사
 defaultjosa = 체언의 마지막 받침을 알 수 없는 경우에 defaultjosa 값을 쓴다.
 override = True/False : True이면 체언의 어미에 상관없이 defaultjosa (없다면 josa) 값을 쓴다.
 josaonly = True/False: True이면 체언 부분은 생략한다. (복잡한 틀 설계용)
 

function func.josa(frame)
 local input_string = frame.args.str or frame.args[1] or ''
 local input_josa = frame.args.josa or frame.args[2] or ''
 local input_defaultjosa = frame.args.defaultjosa
 local override = getBoolean(frame.args.override or false)
 local josaonly = getBoolean(frame.args.josaonly or false)

 local output_josa

 if override then
 output_josa = input_defaultjosa or input_josa
 else
 local char_class = finalclass(input_string)
 if char_class == final_vowel then
 output_josa = finalform_vowel[input_josa] or input_josa
 elseif char_class == final_consonant then
 output_josa = finalform_consonant[input_josa] or input_josa
 elseif char_class == final_rieul then
 output_josa = finalform_rieul[input_josa] or input_josa
 else -- final_unknown
 output_josa = input_defaultjosa or finalform_basic[input_josa] or input_josa
 end
 -- mw.log (input_string .. '[' .. char_class .. ']' .. output_josa)
 end
 
 if josaonly then
 return output_josa
 else
 return input_string .. output_josa
 end
end

-- 동음이의어 구분이 된 문서 링크를 간편하게 처리 
function func.pipetrick(frame)
 local input_string = (frame.args[1] or '')
 local input_title = frame.args[2]
 local first_char = string.sub
 
 if first_char == '[' then
 return input_string
 elseif first_char == ':' then
 input_string = string.sub
 end
 
 local title_part = input_title or string.gsub(input_string, ' %(.*%)$', '')

 if title_part == input_string then
 return ':' .. input_string .. ''
 else
 return '' .. title_part .. ''
 end
end

local langdata = mw.loadData('Module:Langname/data')

function func.langdata(frame)
 codes = {}
 for k, v in pairs(langdata.lang_name) do
 table.insert
 end
 
 table.sort(codes)
 
 for i, code in ipairs(codes) do
 l1 = langdata.lang_name[code]
 l2 = mw.language.fetchLanguageName
 if l1 ~= l2 then
 mw.log(string.format)
 end
 end
end

 
function func.langname(frame)
 local code = frame.args.code or frame.args.code[1]
 local lang = frame.args.lang or frame.args.code[2]
 
 return mw.language.fetchLanguageName
end

return func