Open main menu

Wiktionary β

Module:zh

General-purpose utilities module for Chinese. This module uses Module:zh/data and Module:zh/data/skeys to store its data.

FunctionsEdit

  1. rs
    {{#invoke:zh|sortkey_conv|纟04}} → 糸04
  2. skeys
    {{#invoke:zh|skeys|快}} → 心04
  3. ts
    {{#invoke:zh|ts|試試我吧!}} → 试试我吧!
  4. st
    {{#invoke:zh|st|试试我吧!}} → 試試我吧!
  5. py_detone
    {{#invoke:zh|py_detone|shì}} → shi
  6. py_transf
    {{#invoke:zh|py_transf|shì}} → shi4
  7. tone_determ
    {{#invoke:zh|tone_determ|shì}} → 4
  8. ts_determ
    {{#invoke:zh|ts_determ|試試我}} → trad
  9. py
    {{#invoke:zh|py|試}} → shì
  10. decomp
    {{#invoke:zh|decomp|分解開來|2}} → 解
  11. compdecomp
    {{#invoke:zh|compdecomp|葉綠體|21}}葉綠
  12. hzbox
    {{#invoke:zh|hzbox|光合作用}} → {{zh-forms}}
    {{#invoke:zh|hzbox|光合作用|22}} → {{zh-forms|type=22}}
    {{#invoke:zh|hzbox|葉綠體}} → {{zh-forms|s=叶绿体}}
    {{#invoke:zh|hzbox|葉綠體|21}} → {{zh-forms|s=叶绿体|type=21}}

local M = {}

local m_skeys = nil
local len = mw.ustring.len
local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local match = mw.ustring.match
local cmn_pron = nil

local tones = '[̄́̌̀]'

local pos_aliases_title = {
	["n"] = "Noun", 
	["pn"] = "Proper noun", 
	["propn"] = "Proper noun", 
	["pron"] = "Pronoun", 
	["v"] = "Verb", 
	["a"] = "Adjective", 
	["adj"] = "Adjective", 
	["adv"] = "Adverb", 
	["prep"] = "Preposition", 
	["postp"] = "Postposition", 
	["conj"] = "Conjunction", 
	["part"] = "Particle", 
	["suf"] = "Suffix", 
	["prov"] = "Proverb", 
	["id"] = "Idiom", 
	["ch"] = "Idiom", 
	["cy"] = "Idiom", 
	["ph"] = "Phrase", 
	["intj"] = "Interjection", 
	["cl"] = "Classifier", 
	["num"] = "Numeral", 
	["abb"] = "Abbreviation", 
	["deter"] = "Determiner",
}

local pos_aliases_head = {
	["n"] = "noun", 
	["pn"] = "proper noun", 
	["propn"] = "proper noun", 
	["v"] = "verb", 
	["a"] = "adj",
	["postp"] = "post", 
	["conj"] = "con", 
	["part"] = "particle", 
	["pron"] = "pronoun", 
	["prov"] = "proverb", 
	["id"] = "idiom", 
	["ch"] = "idiom", 
	["cy"] = "idiom", 
	["ph"] = "phrase", 
	["intj"] = "interj", 
	["abb"] = "abbr", 
	["cl"] = "cls", 
	["deter"] = "det",
}

local function replace_chars(s, tab)
	return mw.ustring.gsub(s, ".", tab)
end

function M.sortkey_conv(f)
	local m_sort_data = mw.loadData("Module:zh/data/sortkey")
	local rs = type(f) == 'table' and f.args[1] or f
	local ch = sub(rs,1,1)
	ch = m_sort_data.sortkeys[ch] or ch
	return ch .. sub(rs, 2, len(rs))
end

function M.py_detone(f)
	local text = type(f) == 'table' and f.args[1] or f
	return mw.ustring.toNFC(gsub(mw.ustring.toNFD(text), tones, ''))
end

function M.py_transf(f)
	local text = type(f) == 'table' and f.args[1] or f
	return M.py_detone(text) .. M.tone_determ(text)
end

function M.tone_determ(f)
	local text = type(f) == 'table' and f.args[1] or f
	text = mw.ustring.toNFD(text)
	local tone_num = { ['̄'] = '1', ['́'] = '2', ['̌'] = '3', ['̀'] = '4' }
	return tone_num[match(text, tones)] or '5'
end

function M.ts_determ(f)
	local m_ts_data = mw.loadData("Module:zh/data/ts")
	local m_st_data = mw.loadData("Module:zh/data/st")
	local text = type(f) == 'table' and f.args[1] or f
	local i = 0
	for cp in mw.ustring.gcodepoint(text) do
		local ch = mw.ustring.char(cp)
		if m_ts_data.ts[ch] then return 'trad' end
		if m_st_data.st[ch] then if i > 1 then return 'simp' else i = i + 1 end end
	end
	return (i > 0 and 'simp' or 'both')
end

function M.ts(f)
	local m_ts_data = mw.loadData("Module:zh/data/ts")
	local text = type(f) == 'table' and f.args[1] or f
	text = replace_chars(text, m_ts_data.ts)
	return text
end

function M.st(f)
	local m_st_data = mw.loadData("Module:zh/data/st")
	local text = type(f) == 'table' and f.args[1] or f
	text = replace_chars(text, m_st_data.st)
	return text
end

function M.py(text,comp,pos,p,is_erhua)
	local m_cmn_pron = mw.loadData("Module:zh/data/cmn-pron")
	if not is_erhua then is_erhua = false end
	if type(text) == 'table' then text,comp,pos,p,is_erhua = text.args[1],text.args[2],text.args[3],text.args[4],text.args[5] end
	comp = comp or ''
	local q = {}
	local sum = 0
	length = len(text)
	if is_erhua then length = length - 1 end
	textconv = text
	text = ''
	if comp ~= '' and comp ~= '12' and comp ~= '21' and not ((pos == 'cy' or pos == 'Idiom' or pos == 'idiom') and length == 4) and not is_erhua then
		for i = 1, len(comp) do
			sum = sum + tonumber(sub(comp,i,i))
			q[sum] = 'y'
		end
	end
	if not p then p={} end
	local initial = true
	for i = 1, length do
		if p[i] and p[i] ~= '' then --pronunciation supplied
			text = text .. p[i]
		else
			local char = sub(textconv,i,i)
			char = m_cmn_pron.py[char] or m_cmn_pron.py[M.ts(char)] or char
			if is_erhua or initial or not mw.ustring.find(char,'^[aoeāōēáóéǎǒěàòè]') then
				text = text .. char
			else
				text = text .. "'" .. char
			end
			
			initial = char == sub(textconv,i,i) and sub(textconv,i-3,i) ~= "</b>" --the second condition checks for closing bold tag
		end
		if q[i] == 'y' and i ~= length and not is_erhua then text = text .. ' ' end
	end
	if is_erhua then text = text .. 'r' end
	if pos == 'pn' or pos == 'propn' then
		characters = mw.text.split(text,' ')
		for i=1,#characters do
			characters[i] = mw.language.getContentLanguage():ucfirst(characters[i])
		end
		text = table.concat(characters,' ')
	end
	return text
end

function M.py_er(text,comp,pos,p)
	return M.py(text,comp,pos,p,true)
end

function M.pytemp(text,comp,pos,p,is_erhua)
	local m_cmn_pron = mw.loadData("Module:zh/data/cmn-pron")
	local wordlist_1, wordlist_2, wordlist_3 = mw.loadData("Module:zh/data/wordlist/1"), mw.loadData("Module:zh/data/wordlist/2"), mw.loadData("Module:zh/data/wordlist/3")
	if not is_erhua then is_erhua = false end
	if type(text) == 'table' then text,comp,pos = text.args[1],text.args[2],text.args[3] or 'n' end
	comp = comp or ''
	local q = {}
	local sum = 0
	wordlist_result = wordlist_1[text] or wordlist_2[text] or wordlist_3[text] or nil
	moe_pron = wordlist_result and mw.text.split(wordlist_result, " ") or {}
	textconv = M.ts(text)
	length = len(text)
	if is_erhua == true then
		length = length - 1
		textconv = sub(textconv, 1, length)
	end
	text = ''
	if comp ~= '' and comp ~= '12' and comp ~= '21' and not is_erhua then
		for i = 1, len(comp) do
			sum = sum + tonumber(sub(comp,i,i))
			q[sum] = 'y'
		end
	end
	if not p then p={} end
	for i = 1, length do
		if p[i] and p[i] ~= '' then --pronunciation supplied
			text = text .. p[i]
		else
			local char = sub(textconv,i,i)
			if mw.ustring.find(char,'[一不期績绩蹟跡迹嵌框微突帆藩擊击夾夹鞠拈夕汐矽昔惜息危椰濤涛叔寂馴驯築筑質质播究菌矻識识穴膜餾馏企辱署偽伪蹈諷讽斂敛坊樸朴儲储剖檔档髮轍辙賜赐堤壑酵括懾慑蝸蜗淆攜携崖癌暫暂蟄蛰驟骤液血酪嘌覲幀蕁曳室癬癣亞亚穹褐貯贮淑場场踮鱒跌擁綏胺翕煦伐髮眶]') then
				text = text .. char
			else
				char = moe_pron[i] or m_cmn_pron.py[char] or char
				if i ~= 1 and mw.ustring.find(char,'^[aoeāōēáóéǎǒěàòè]') then
					char = "'" .. char
				end
				text = text .. char
			end
		end
		if q[i] == 'y' and i ~= length and not is_erhua and pos ~= 'cy' then text = text .. ' ' end
	end
	text = gsub(text," '"," ")
	if pos == 'pn' or pos == 'propn' then
		characters = mw.text.split(text,' ')
		for i=1,#characters do
			characters[i] = mw.language.getContentLanguage():ucfirst(characters[i])
		end
		text = table.concat(characters,' ')
	end
	return text
end

function M.pytemp_er(text,comp,pos,p)
	return M.pytemp(text,comp,pos,p,true)
end

function M.pywordconv(text,p)
	local m_cmn_pron = mw.loadData("Module:zh/data/cmn-pron")
	if type(text) == 'table' then text = text.args[1] end
	textconv = M.ts(text)
	length = len(text)
	text = ''
	if not p then p = {} for i = 1, 20 do p[i] = '' end end
	for i = 1, length do
		if p[i] ~= '' then
			text = text .. M.py_transf(p[i])
		else
			char = sub(textconv,i,i)
			cpy = m_cmn_pron.py[char] or char
			text = text .. M.py_transf(cpy)
		end
	end
	return text
end

function M.pywordconv_er(text,p)
	local m_cmn_pron = mw.loadData("Module:zh/data/cmn-pron")
	if type(text) == 'table' then text = text.args[1] end
	length = len(text) - 1
	textconv = sub(M.ts(text),1,length)
	text = ''
	if not p then p={} for i=1,20 do p[i]='' end end
	for i = 1,length do
		if p[i] ~= '' then
			if i == length then p[i] = p[i] .. 'r' end
			text = text .. M.py_transf(p[i])
		else
			char = sub(textconv,i,i)
			cpy = m_cmn_pron.py[char] or char
			if i == length then cpy = cpy .. 'r' end
			text = text .. M.py_transf(cpy)
		end
	end
	return text
end

function M.decomp(text,comp)
	if type(text) == 'table' then text,comp = text.args[1],text.args[2] or '' end
	comp = comp or tostring(len(text))
	local num = tonumber(comp)
	char = sub(text,num,num)
	return char
end

function M.compdecomp(title,comp)
	if type(title) == 'table' then title,comp = title.args[1],title.args[2] end
	comp = comp or ''
	local start = 1
	local finish = 1
	local sum = 0
	local text = ''
	local p={}
	textlen = len(title)
	if comp == '' then
		for i = 1,textlen do
			comp = comp .. '1'
		end
	end
	for i = 1, len(comp) do
		p[i] = tonumber(sub(comp,i,i))
		sum = sum + p[i]
	end
	if sum ~= textlen then
		comp = ''
		for j = 1,textlen do
			p[j] = tonumber(1)
			comp = comp .. '1'
		end
	end
	for i = 1, len(comp) do
		if i ~= 1 then start = start + p[i-1] end
		finish = start + p[i] - 1
		text = (text .. '[[' .. sub(title,start,finish) .. ']]')
	end
	return text
end

function M.compdecompetym(title,comp)
	if type(title) == 'table' then title,comp = title.args[1],title.args[2] end
	comp = comp or ''
	local start = 1
	local finish = 1
	local sum = 0
	local text = ''
	local p={}
	textlen = len(title)
	if comp == '' then
		for i = 1,textlen do
			comp = (comp .. '1')
		end
	end
	for i = 1, len(comp) do
		p[i] = tonumber(sub(comp,i,i))
		sum = sum + p[i]
	end
	if sum ~= textlen then
		comp = ''
		for j = 1,textlen do
			p[j] = tonumber(1)
			comp = (comp .. '1')
		end
	end
	for i = 1, len(comp) do
		if i ~= 1 then start = start + p[i-1] end
		finish = start + p[i] - 1
		if i ~= 1 then text = (text .. '|') end
		text = (text .. sub(title,start,finish))
	end
	return text
end

function M.hzbox(title,comp,e,alt,gloss,lit,t2)
	if type(title) == 'table' then title,comp = title.args[1],title.args[2] end
	local id = M.ts_determ(title)
	local text = '{{zh-forms'
	if e and e ~= "" then text = text .. '|' .. e end
	if id == 'simp' then
		text = text .. '|t=' .. M.st(title)
	elseif id == 'trad' then
		text = text .. '|s=' .. M.ts(title)
	end
	text = text .. ((t2 and t2 ~= "") and ('|t2=' .. t2) or '')
	text = text .. ((comp and comp ~= "") and ('|type=' .. comp) or '')
	text = text .. ((alt and alt ~= "") and '|alt=' .. alt or '')
	text = text .. ((gloss and gloss ~= "") and '|gloss=' .. gloss or '')
	text = text .. ((lit and lit ~= "") and '|lit=' .. lit or '')
	return text .. '}}'
end

function M.hzbox_er(title)
	if type(title) == 'table' then title = title.args[1] end
	length = len(title)
	if sub(title, length, length) == '兒' then id = 'trad' else id = 'simp' end
	title = sub(title, 1, length-1)
	text = '{{zh-hanzi-box|'
	if id == 'simp' then
		text = (text .. '[[' .. title .. ']][[儿]]|[[' .. M.st(title) .. '兒]]}}')
	else
		text = (text .. '[[' .. M.ts(title) .. '儿]]|[[' .. title .. ']][[兒]]}}')
	end
	return text
end

function M.sort(title)
	local m_cmn_pron = mw.loadData("Module:zh/data/cmn-pron")
	if type(title) == 'table' then title = title.args[1] end
	local text = ''
	length = len(title)
	title = M.ts(title)
	for i = 1,length do
		charpy = sub(title,i,i)
		charpy = m_cmn_pron.py[charpy] or charpy
		text = text .. M.py_transf(charpy)
	end
	return text
end

function M.postitle(pos)
	pos = pos or ''
	if pos == '' then pos = 'n' end
	return pos_aliases_title[pos] or pos
end

function M.poshead(pos)
	pos = pos or ''
	if pos == '' then pos = 'n' end
	return pos_aliases_head[pos] or pos
end

-- Deprecated. Use the makeSortKey function in [[Module:zh-sortkey]] instead.
function M.skeys(title)
	if m_skeys == nil then m_skeys = mw.loadData('Module:zh/data/skeys') end
	
	if type(title) == 'table' then title = title.args[1] end
	local text = sub(title,1,1)
	text = m_skeys.skeys[text] or text
	return text
end

function M.chardecomp(title)
	if type(title) == 'table' then title = title.args[1] end
	text = mw.text.split(title,"")
	return table.concat(text,"|")
end

function M.semantics(text,name,sem)
	if sem[1] and sem[1] ~= '' then
		text = (text .. '\n\n====' .. name .. '====')
		if name == 'Derived terms' then
			text = text .. '\n{{zh-der'
			for i = 1, #sem do
				text = text .. '|' .. sem[i]
			end
			text = text .. '}}'
		else
			for i = 1, #sem do
				text = text .. '\n* {{zh-l|' .. sem[i] .. '}}'
			end
		end
	end
	return text
end

function M.create_er(f)
	return M.create(f,true)
end

local function checkpos(pos)
	for poscode,posname in pairs(pos_aliases_head) do
		if pos == posname then
			return poscode
		end
	end
	for poscode,posname in pairs(pos_aliases_title) do
		if pos == posname then
			return poscode
		end
	end
	return pos
end

function M.headword(title,comp,pos,is_erhua)
	if not is_erhua then is_erhua = false end
	is_table = (type(title) == 'table')
	p = {}
	for i=4,23 do table.insert(p,(is_table and title.args[i] or '')) end
	if type(title) == 'table' then title,comp,pos = title.args[1],title.args[2],title.args[3] end
	text = '{{zh-' .. M.poshead(pos) .. '|'
	id = M.ts_determ(title)
	if id == 'both' then text = text .. 'ts' elseif id == 'simp' then text = text .. 's' else text = text .. 't' end
	if is_erhua then
		text = text .. '|pin=' .. M.py_er(title,comp,pos,p) .. '|pint=' .. M.pywordconv_er(title,p)
		if id == 'simp' then
			text = text .. '|tra=' .. M.st(title) .. '|sim=' .. title
		else
			text = text .. '|tra=' .. title .. '|sim=' .. M.ts(title)
		end
		text = text .. '}}\n\n# {{erhua form'
		if def ~= '' then text = text .. '|' .. def end
	else
		text = text .. '|pin=' .. M.py(title,comp,pos,p) .. '|pint=' .. M.pywordconv(title,p)
		if id == 'simp' then
			text = text .. '|tra=' .. M.st(title) .. '|sim=' .. title
		elseif id == 'trad' then
			text = text .. '|tra=' .. title .. '|sim=' .. M.ts(title)
		end
	end
	return text .. '}}'
end

function M.link(frame, mention, args, pagename, no_transcript)
	local params = {
		[1] = {},
		[2] = {},
		[3] = {},
		[4] = {},
		['gloss'] = {},
		['tr'] = {},
	}
	
	if mention then
		params['note'] = {}
	end
	
	local moduleCalled
	if args then
		moduleCalled = true
	end
	args = args or frame:getParent().args
	if not moduleCalled then
		params[1].required = true
	end
	args = require("Module:parameters").process(args, params)
	if moduleCalled then
		if not args[1] then
			return ""
		end
	end
	pagename = pagename or mw.title.getCurrentTitle().text
	
	local text, tr, gloss, word, content, template
	
	if args[2] and match(args[2], '[一-龯㐀-䶵]') then
		gloss = args[4]
		tr = args[3]
		text = args[1] .. '/' .. args[2]
	else
		text = args[1]
		if args['gloss'] then
			tr = args[2]
			gloss = args['gloss']
		else
			if args[3] or (args[2] and (match(args[2], '[āōēīūǖáóéíúǘǎǒěǐǔǚàòèìùǜâêîôû̍ⁿ]') or match(args[2], '[bcdfghjklmnpqrstwz]h?y?[aeiou][aeiou]?[iumnptk]?g?[1-9]'))) then
				tr = args[2]
				gloss = args[3]
			else
				gloss = args[2]
			end
		end
	end
	if args['tr'] then
		tr = args['tr']
		gloss = gloss or args[2]
	end
	if text then
		if not text:match('[%[%]]') then
			words = mw.text.split(text, "/", true)
			if #words == 1 and M.ts_determ(words[1]) == 'trad' and not match(words[1], '%*') then
				table.insert(words, M.ts(words[1]))
			end
			if not tr and not no_transcript and words[1] and text ~= pagename and mw.title.new(words[1]).exists then
				content = mw.title.new(words[1]):getContent()
				content = gsub(content, ",([^ ])", ";%1")
				template = match(content, "{{zh%-pron[^}]*|m=([^};|\n]+)")
				if template and template ~= "" then
					if cmn_pron == nil then
					   cmn_pron = require("Module:cmn-pron")
					end
					tr = cmn_pron.str_analysis(template, 'link')
				end
			end
		
			for i, word in ipairs(words) do
				word = gsub(word, '%*', '')
				if mention then
					words[i] = '<i class="Hani mention" lang="zh">[[' .. word .. '#Chinese|' .. word .. ']]</i>'
	--[[ (disabled to allow links to, for example, a link to 冥王星#Chinese from 冥王星#Japanese. 18 May, 2016)
				elseif word == pagename then
					word = '<span class="Hani" lang="zh"><b>' .. word .. '</b></span>'
	]]
				else
					words[i] = '<span class="Hani" lang="zh">[[' .. word .. '#Chinese|' .. word .. ']]</span>'
				end
			end
			text = table.concat(words, "/")
		elseif text:match('[%[%]]') or text == pagename then
			if mention then
				text = '<i class="Hani mention" lang="zh">' .. mw.ustring.gsub(text, "%*", "") .. '</i>'
			else
				text = '<span class="Hani" lang="zh">' .. mw.ustring.gsub(text, "%*", "") .. '</span>'
			end
		end
	end
	if tr == '-' or no_transcript then
		tr = nil -- allow translit to be disabled: remove translit if it is "-", just like normal {{l}}
	end
	local notes = args['note']
	if tr or gloss  or notes then
		local annotations = {}
		if tr then
			tr = '<i><span class="tr Latn">' .. tr .. '</span></i>'
			table.insert(annotations, tr)
		end
		if gloss then
			table.insert(annotations, '“' .. gloss .. '”')
		end
		table.insert(annotations, notes)
		annotations = table.concat(annotations, ", ")
		text = text .. " (" .. annotations .. ")"
	end
	return text
end

function M.mention(frame)
	return M.link(frame, true)
end

function M.check_pron(text, variety, length, entry_creation)
	if type(text) == 'table' then text, variety = text.args[1], text.args[2] end
	if not text then
		return
	end
	startpoint, address = { ['yue'] = 51, ['hak'] = 19968, ['nan'] = 19968 }, { ['yue'] = 'Jyutping_word/%03d', ['hak'] = 'hak-pron/%02d', ['nan'] = 'nan-pron/%03d' }
	unit = 1000
	first_char = sub(text, 1, 1)
	codepoints = { ['simp'] = mw.ustring.codepoint(first_char), ['trad'] = mw.ustring.codepoint(M.st(first_char)) }
	texts = { ['simp'] = text, ['trad'] = M.st(text) }
	local result = false
	for identity, codepoint in pairs(codepoints) do
		if length == 1 and variety == "yue" then
			success, data = pcall(mw.loadData, 'Module:zh/data/Jyutping character')
		else
			page_index = math.floor((codepoint - startpoint[variety]) / unit)
			success, data = pcall(mw.loadData,
				('Module:zh/data/' .. address[variety]):format(page_index)
			)
		end
		if success then
			result = data[texts[identity]] or false
		else
			result = false
		end
		if result then
			if variety == "nan" and entry_creation then
				result = gsub(result, "%-á%-", "-仔-")
				result = gsub(result, "%-á/", "-仔/")
				result = gsub(result, "%-á$", "-仔")
				result = gsub(result, "^(.+)%-%1%-%1$", "(%1)")
				result = gsub(result, "^(.+)%-%1%-%1([%-%/])", "(%1)%2")
				result = gsub(result, "([%-%/])(.+)%-%1%-%1$", "%1(%2)")
				result = gsub(result, "([%-%/])(.+)%-%1%-%1([%-%/])", "%1(%2)%3")
			end
			return result
		end
	end
	return result
end

function M.nan_for_bot()
	text = mw.title.getCurrentTitle().text
	result = M.check_pron(text, 'nan')
	if result then
		return '\n|mn=' .. result
	else
		return
	end
end

function M.der(frame)
	local params = {
		[1] = { list = true },
		["fold"] = { type = "boolean" },
		["title"] = {},
		["hide_pron"] = { type = "boolean" },
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	local pagename = mw.title.getCurrentTitle().text
	local result = {}
	
	local fold = args["fold"]
	local title = args["title"] and " (<i>" .. args["title"] .. "</i>)" or ""
	local saurus = mw.title.getCurrentTitle().nsText == "Wikisaurus" and true or false
	local no_transcript = args["hide_pron"]
	
	for i, word in ipairs(args[1]) do
		table.insert(result, word and M.link(frame, nil, mw.text.split(word, ":"), pagename, no_transcript))
	end
	
	return 
		require("Module:columns").create_table(
			(len(pagename) > 1 and 2 or 3), 
			result, 
			1, 
			"#F5F5FF",
			(((#result > 72 or fold) and not saurus) and true or false), 
			"Derived terms",
			"Derived terms from <span lang=\"zh\" class=\"Hani\">" .. pagename .. "</span>" .. title, 
			math.floor(80 / (len(pagename) > 1 and 2 or 3)), 
			"* ", 
			nil
		)
end

local lang_abbrev = {
	['m'] = 'Mandarin',
	['c'] = 'Cantonese', ['g'] = 'Gan', ['h'] = 'Hakka', ['j'] = 'Jin',
	['md'] = 'Min Dong', ['mn'] = 'Min Nan', ['mn-t'] = 'Teochew',
	['w'] = 'Wu', ['x'] = 'Xiang',
}

function M.cls(frame)
	local args = frame:getParent().args
	local result, categories = {}, {}
	local m_zh_cat = require("Module:zh-cat")
	local space = '<span style="padding-left:4px; padding-right:4px">&nbsp;</span>'
	for i, combination in ipairs(args) do
		local part = mw.text.split(combination, ":")
		if #part == 2 then
			local dialect = { "" }
			local function annotate(main_text, annotation)
				return "<span style=\"border-bottom: 1px dotted #000; cursor:help\" " ..
					"title=\"" .. annotation .. "\"><i>" .. main_text .. "</i></span>"
			end
			for variety in mw.text.gsplit(part[1], ",") do
				table.insert(dialect, annotate(variety, lang_abbrev[variety]))
			end
			note = table.concat(dialect, " ")
		else
			note = false
		end
		table.insert(result, M.link(frame, nil, { part[2] or part[1], tr = "-" }, pagename) ..
			(note or ""))
		table.insert(categories, m_zh_cat.categorize("Classifier:" .. (part[2] or part[1])))
	end
	return "<span style=\"padding-left:15px; font-size:80%\"><span style=\"background:#EDFFFF\">(''Classifier'': " ..
		table.concat(result, ";" .. space) .. ")</span></span>" .. 
		(mw.title.getCurrentTitle().nsText == "" and table.concat(categories) or "")
end

function M.newDer(frame)
	local title = mw.title.getCurrentTitle().subpageText
	local prefix = "Module:zh/data/wordlist/"
	local args = frame:getParent().args
	
	local limit = args["limit"] and tonumber(args["limit"]) or false
	local char_pronunciation = args["p"] or false
	local fold = args["fold"] or false
	local hide_pron = args["hide_pron"] or false
	
	local result = {}
	for _, arg in ipairs(args) do
		table.insert(result, arg)
	end
	
	i = 1
	while i < 4 do
		local wordlist = require(prefix .. tostring(i))
		for word, pronunciation in pairs(wordlist) do
			if match(word, title) and word ~= title and not (len(title) == 1 and len(word) > (limit or 4)) then
				if char_pronunciation then
					if mw.text.split(pronunciation, " ")[mw.ustring.find(word, title)] == char_pronunciation then
						table.insert(result, word)
					end
				else
					table.insert(result, word)
				end
			end
		end
		i = i + 1
	end
	local hash, res = {}, {}
	for _, element in ipairs(result) do
		local section = mw.text.split(element, ":")[1]
		if not hash[section] then
			res[#res + 1] = element
			hash[section] = true
		end
	end
	return "{{zh-der|" .. (hide_pron and "hide_pron=1|" or "") .. (fold and "fold=1|" or "") .. table.concat(res, "|") .. "}}"
end

function M.create(f,is_erhua)
	if not is_erhua then is_erhua = false end
	local title = mw.title.getCurrentTitle().text
	local params = {
		["type"] = {}, ["comp"] = {alias_of = "type"},
		[1] = {list = true, allow_holes = true},
		["pos"] = {list = true, allow_holes = true},
		["def"] = {list = true, allow_holes = true},
		["e1"] = {list = "e", allow_holes=true}, ["etym1"] = {list = "etym", allow_holes=true}, ["etymology1"] = {list = "etymology", allow_holes=true}, ["meaning"] = {list = true, allow_holes=true},
		["k"] = {}, ["ko"] = {alias_of = "k"}, ["korean"] = {alias_of = "k"},
		["kt"] = {}, ["tr"] = {alias_of = "kt"}, ["transcription"] = {alias_of = "kt"}, ["ktr"] = {alias_of = "kt"}, ["kotr"] = {alias_of = "kt"}, ["koreantr"] = {alias_of = "kt"}, ["ktrans"] = {alias_of = "kt"}, ["kotrans"] = {alias_of = "kt"},
		["ke"] = {}, ["kodef"] = {alias_of = "ke"}, ["kodefinition"] = {alias_of = "ke"}, ["koreandef"] = {alias_of = "ke"},
		["v"] = {}, ["vi"] = {alias_of = "v"}, ["vietnam"] = {alias_of = "v"},
		["ve"] = {}, ["videf"] = {alias_of = "ve"}, ["videfinition"] = {alias_of = "ve"}, ["vietnamdef"] = {alias_of = "ve"}, ["vietnamdefinition"] = {alias_of = "ve"},
		["p"] = {list = true, allow_holes=true}, ["pron"] = {list = true, allow_holes=true}, ["pronunciation"] = {list = true, allow_holes=true},
		["e"] = {}, ["etym"] = {alias_of = "e"}, ["etymology"] = {alias_of = "e"}, ["origin"] = {alias_of = "e"}, ["ori"] = {alias_of = "e"}, ["o"] = {alias_of = "e"},
		["syn"] = {list = true}, ["synonym"] = {list = true},
		["ant"] = {list = true}, ["antonym"] = {list = true},
		["der"] = {list = true}, ["deriv"] = {list = true}, ["derived"] = {list = true}, ["derivedterm"] = {list = true},
		["also"] = {list = true}, ["see"] = {list = true}, ["seealso"] = {list = true}, ["alsosee"] = {list = true},
		["wp"] = {}, ["wiki"] = {alias_of = "wp"}, ["wikipedia"] = {alias_of = "wp"},
		["cat"] = {list = true}, ["category"] = {list = true}, ["categories"] = {list = true}, ["categorize"] = {list = true}, ["categorise"] = {list = true}, ["categorization"] = {list = true}, ["categorisation"] = {list = true},
		["pic"] = {}, ["file"] = {alias_of = "pic"}, ["image"] = {alias_of = "pic"}, ["picture"] = {alias_of = "pic"},
		["piccap"] = {}, ["caption"] = {alias_of = "piccap"}, ["description"] = {alias_of = "piccap"}, ["desc"] = {alias_of = "piccap"},
		["er"] = {}, ["erhua"] = {alias_of = "er"},
		["tl"] = {}, ["toneless"] = {alias_of = "tl"}, ["tonelessvariant"] = {alias_of = "tl"}, ["variant"] = {alias_of = "tl"}, ["variation"] = {alias_of = "tl"}, ["tonelessvariation"] = {alias_of = "tl"},
		["a"] = {}, ["audio"] = {alias_of = "a"}, ["listen"] = {alias_of = "a"}, ["sound"] = {alias_of = "a"}, ["pronounced"] = {alias_of = "a"},
		["alt"] = {}, ["alter"] = {alias_of = "alt"}, ["altern"] = {alias_of = "alt"}, ["alternate"] = {alias_of = "alt"}, ["alternative"] = {alias_of = "alt"},
		["c"] = {}, ["cant"] = {alias_of = "c"}, ["cantonese"] = {alias_of = "c"},
		["mn"] = {}, ["nan"] = {alias_of = "mn"}, ["minnan"] = {alias_of = "mn"},
		["w"] = {}, ["wu"] = {alias_of = "w"}, ["shanghai"] = {alias_of = "w"},
		["m"] = {},
		["m-s"] = {},
		["c-t"] = {},
		["g"] = {},
		["h"] = {},
		["j"] = {},
		["md"] = {},
		["mn-t"] = {},
		["x"] = {},
		["mc"] = {},
		["oc"] = {},
		["ts"] = {},
		["gloss"] = {},
		["lit"] = {},
		["t2"] = {},
	}
	local args = require("Module:parameters").process(f:getParent().args, params)
	local comp = args["type"] or ""
	local pos = {}
	local def = {}
	for i=1,math.max(args[1].maxindex/2, args["pos"].maxindex, args["def"].maxindex) do
		table.insert(pos, args[1][2*i-1] or args["pos"][i] or "")
		table.insert(def, args[1][2*i] or args["def"][i] or "")
	end
	
	local function length(array)
		return array.maxindex or #array
	end
	
	local function expand(arg)
		local result = {}
		local maximum = 0
		for i=1,#arg do if length(arg[i]) > maximum then maximum = length(arg[i]) end end
		local current = nil
		for i=1,maximum do
			current = nil
			for j=1,#arg do
				if current then
					break
				else
					current = arg[j][i]
				end
			end
			current = current or ""
			table.insert(result, current)
		end
		return result
	end
	
	local function fetch_all(arg)
		local result = {}
		for i=1,#arg do
			for j=1,#arg[i] do
				table.insert(result,arg[i][j])
			end
		end
		return result
	end
	
	local etyms = expand({args["e1"], args["etym1"], args["etymology1"], args["meaning"]})
	local ko = args["k"] or ""
	local kotrans = args["kt"] or ""
	local kodef = args["ke"] or def[1] or ""
	local vi = args["v"] or ""
	local videf = args["ve"] or def[1] or ""
	local p = expand({args["p"], args["pron"], args["pronunciation"]})
	local etym = args["e"] or ""
	local syn = expand({args["syn"], args["synonym"]})
	local ant = expand({args["ant"], args["antonym"]})
	local der = expand({args["der"], args["deriv"], args["derived"], args["derivedterm"]})
	local also = expand({args["also"], args["see"], args["alsosee"], args["seealso"]})
	local wp = args["wp"] or ""
	local cat = fetch_all({args["cat"], args["category"], args["categories"], args["categorize"], args["categorise"], args["categorization"], args["categorisation"]})
	local pic = args["pic"] or ""
	local piccap = args["piccap"] or ""
	local er = args["er"] or ""
	local tl = args["tl"] or ""
	local audio = args["a"] or ""
	local alt = args["alt"] or ""
	local m_s = args["m-s"] or ""
	local c = args["c"] or ""
	local c_t = args["c-t"] or ""
	local mn = args["mn"] or ""
	local mn_t = args["mn-t"] or ""
	local w = args["w"] or ""
	local m = args["m"] or ""
	local h = args["h"] or ""
	local g = args["g"] or ""
	local j = args["j"] or ""
	local x = args["x"] or ""
	local md = args["md"] or ""
	local mc = args["mc"] or ""
	local oc = args["oc"] or ""
	local ts = args["ts"] or ""
	local gloss = args["gloss"] or ""
	local lit = args["lit"] or ""
	local t2 = args["t2"] or ""
	text = ''
	if not pos[1] or pos[1] == '' then pos[1] = 'n' end
	for i=1,#pos do pos[i] = checkpos(pos[i]) end
	text = (text .. '==Chinese==\n')
	if M.ts_determ(title) == 'simp' and ts ~= "trad" then
		return text .. '{{zh-see|' .. M.st(title) .. ('}}'):format(mw.title.getCurrentTitle().text)
	end
	length = len(title)
	noerhua = sub(title,1,length-1)
	erhua = sub(title,length,length)
	text = text .. (is_erhua and M.hzbox_er(title) or M.hzbox(title,comp,table.concat(etyms,'|'),alt,gloss,lit,t2))
	if wp ~= '' then text = (text .. '\n{{zh-wp' .. (wp ~= 'y' and '|' .. wp or '') .. '}}') end
	if pic ~= '' then text = (text .. '\n[[File:' .. pic .. '|thumb') if piccap ~= '' then text = (text .. '|' .. piccap) end text = (text .. ']]')	end
	if is_erhua then
		text = (text .. '===Pronunciation===\n{{zh-pron\n\|m=' .. M.pytemp_er(title,comp,pos[1],p) .. 'r\n|cat=' .. table.concat(pos[1],',') .. '\n}}\n\n')
	else
		text = (text .. '\n\n')
		if etym ~= '' then text = (text .. '===Etymology===\n' .. etym .. '\n\n') end
		if #etyms > 0 then
			text = (text .. '===Etymology===\n')
			text = (text .. '{{zh-compound|' .. M.compdecompetym(title,comp) .. '|' .. table.concat(etyms,'|') .. '}}\n\n')
		end
		text = (text .. '===Pronunciation===\n{{zh-pron')
		if m ~= '-' then
			if m ~= '' then
				m_pron = m
				text = (text .. '\n|m=' .. m_pron)
			else
				m_pron = gsub(M.pytemp(title,comp,pos[1],p), ',', ', ')
				text = (text .. '\n|m=' .. m_pron)
				if er ~= '' then text = (text .. ',er=' .. er) end
				if tl ~= '' then text = (text .. ',tl=y') end
			end
		end
		if length == 1 or m_s ~= '' then text = (text .. '\n|m-s=' .. (m_s or "")) end
		if c == '' then c = M.check_pron(title, 'yue', length) or '' end
		if length == 1 or (c ~= '' and c ~= '-') then text = (text .. '\n|c=' .. (c or "")) end
		if length == 1 or c_t ~= '' then text = (text .. '\n|c-t=' .. (c_t or "")) end
		if length == 1 or g ~= '' then text = (text .. '\n|g=' .. (g or "")) end
		if h == '' then h = M.check_pron(title, 'hak') or '' end
		if length == 1 or (h ~= '' and h ~= '-') then text = (text .. '\n|h=' .. (h and ("pfs=" .. h) or "")) end
		if length == 1 or j ~= '' then text = (text .. '\n|j=' .. (j or "")) end
		if length == 1 or md ~= '' then text = (text .. '\n|md=' .. (md or "")) end
		if mn == '' then mn = M.check_pron(title, 'nan', nil, true) or '' end
		if length == 1 or (mn ~= '' and mn ~= '-') then text = (text .. '\n|mn=' .. (mn or "")) end
		if length == 1 or mn_t ~= '' then text = (text .. '\n|mn-t=' .. (mn_t or "")) end
		if length == 1 or w ~= '' then text = (text .. '\n|w=' .. (w or "")) end
		if length == 1 or x ~= '' then text = (text .. '\n|x=' .. (x or "")) end
		if audio ~= '' then text = (text .. '\n|ma=') if audio ~= 'y' then text = (text .. audio) else text = (text .. 'y') end end
		if length == 1 or mc ~= '' then text = (text .. '\n|mc=' .. (mc ~= "" and mc or 'y')) end
		if length == 1 or oc ~= '' then text = (text .. '\n|oc=' .. (oc ~= "" and oc or 'y')) end
		text = (text .. '\n|cat=' .. table.concat(pos,',') .. '\n}}\n\n')
	end
	text = (text .. '===' .. (length == 1 and "Definitions" or M.postitle(pos[1])) .. '===\n')
	text = (text .. '{{zh-' .. (length == 1 and "hanzi" or M.poshead(pos[1])) .. '}}\n\n')
	if is_erhua then
		text = text .. '# {{context|Mandarin|lang=zh}} {{erhua form'
		if def[1] and def[1] ~= '' then text = text .. '|' .. def[1] end
		text = text .. '}}'
	else
		text = (text .. '# ' .. ((def[1] and def[1] ~= "") and def[1] or "{{rfdef|lang=zh}}"))
	end
	if syn[1] then
		if match(syn[1], "^dial") then
			text = text .. "\n\n====Synonyms====\n{{zh-" .. syn[1] .. "}}"
		else
			text = M.semantics(text,'Synonyms',syn)
		end
	end
	text = M.semantics(text,'Antonyms',ant)
	text = M.semantics(text,'Derived terms',der)
	for i=2,#pos do
		text = text .. '\n\n===' .. M.postitle(pos[i]) .. '===\n'
		text = text .. '{{zh-' .. M.poshead(pos[i]) .. '}}\n\n'
		if is_erhua then
			text = text .. '# {{context|Mandarin|lang=zh}} {{erhua form'
			if def[i] ~= '' then text = text .. '|' .. def[i] end
			text = text .. '}}'
		else
			text = text .. '# ' .. def[i]
		end
	end
	if #also > 0 then
		text = (text .. '\n\n===See also===')
		for i=1,#also do
			text = (text .. '\n* {{zh-l|' .. also[i] .. '}}')
		end
	end
	if #cat > 0 then text = (text .. '\n\n{{zh-cat|' .. table.concat(cat,'|') .. '}}') end
	if ko ~= '' then
		text = text .. '\n\n----\n\n==Korean==\n{{ko-hanjatab}}\n\n===Noun===\n{{ko-noun|hj|hangeul=' .. ko .. '}}\n\n# {{hanja form of|' .. ko .. '|' .. kodef .. '}}'
	end
	if vi ~= '' then
		text = text .. '\n\n----\n\n==Vietnamese==\n{{vi-hantutab}}\n\n===' .. M.postitle(pos[1]) .. '===\n{{vi-hantu}}\n\n# {{han tu form of|' .. vi .. '|' .. videf .. '}}'
	end
	return text
end

function M.wikipedia(frame)
	local args = frame:getParent().args
	local title = mw.title.getCurrentTitle().text
	local wp_data = {
		["zh"] = { "Written Standard Chinese<sup>[[w:Written vernacular Chinese|?]]</sup>", "Hani", "zh" },
		["cdo"] = { "Min Dong", "cdo" },
		["gan"] = { "Gan", "zh" },
		["hak"] = { "Hakka", "hak" },
		["lzh"] = { "Classical", "zh" },
		["nan"] = { "Min Nan", "nan" },
		["wuu"] = { "Wu", "zh" },
		["yue"] = { "Cantonese", "zh" },
		["en"] = { "English", "en" },
	}
	
	args = args[1] and args or { "zh" }
	result = { '<div class="sister-wikipedia sister-project noprint floatright" style="border: 1px solid #aaa; font-size: 90%; background: #f9f9f9; width: 250px; padding: 4px; text-align: left;"><div style="float: left;">[[File:Wikipedia-logo.png|32px|none|link=|alt=]]</div><div style="margin-left: 40px;">[[Wikipedia]] has ' ..
		(args[2] and "articles" or "an article") .. ' on:' }

	for _, arg in ipairs(args) do
		local part = mw.text.split(arg, ":")
		local lang_data = wp_data[part[1]] or { nil, "Hani", "zh" }
		local annotation = lang_data[1] or false
		if part[1] == "zh" and not args[2] then
			annotation = false
		elseif annotation then
			annotation = " <span style=\"font-size\:80%\">(" .. annotation .. ")</span>"
		end
		script = match(part[2] or title, "[一-龯㐀-䶵]") and "Hani" or "Latn"
		table.insert(result, '<div style="margin-left: 10px;">• <b class="' .. (gsub(script, "Latn", (len(part[2] or title) < 15 and "Latn\" style=\"font-size:120%" or "Latn"))) .. '" lang="' .. lang_data[2] .. '">[[w&#x3a;' .. part[1] .. '&#x3a;' .. (part[2] or title) .. '|' .. (part[2] or title) .. ']]</b>' .. (annotation or "") .. '</div>')
	end
	
	table.insert(result, '</div></div>')
	
	return table.concat(result)
end

function M.saurus(frame)
	local args = frame:getParent().args
	local word = args[1] or mw.title.getCurrentTitle().text
	local content = mw.title.new("Wikisaurus:" .. word):getContent()
	local template = match(content, "{{zh%-list|([^}]+)}}")
	if template and template ~= "" then
		local set = {}
		for item in mw.text.gsplit(template, "|") do
			table.insert(set, item)
		end
		return '<div style="float: right; clear: right; font-size:60%"><span class="plainlinks">[' ..
		tostring(mw.uri.fullUrl("Wikisaurus:" .. word, { ["action"] = "edit" })) ..
		' edit]</span></div></sup>' .. mw.getCurrentFrame():expandTemplate{ title = "Template:zh-list", args = set }
	else
		return ""
	end
end

function M.div(frame)
	local args = frame:getParent().args
	local m_links = require("Module:links")
	local lang = require("Module:languages").getByCode("zh")
	local pagename = mw.title.getCurrentTitle().text
	i, result = 1, ""
	
	local function zh_format(text)
		return '<span class="Hani" lang="zh">' .. text .. '</span>'
	end
	
	local function add_link(pagename, description)
		local target_page = mw.title.new(pagename .. description)
		if target_page.exists and not target_page.isRedirect then
			return zh_format(m_links.language_link({ term = pagename .. description, alt = "~" .. description, lang = lang }))
		else
			return zh_format("~" .. m_links.language_link({ term = description, lang = lang }))
		end
	end

	while args[i] do
		if i ~= 1 then result = result .. "''separator ''" end
		result = result .. add_link(pagename, args[i])
		if i == 1 and args["f"] then
			j = 2
			result = result .. "'', formerly ''" .. add_link(pagename, args["f"])
			while args["f" .. j] do
				result = result .. "'', ''" .. add_link(pagename, args["f" .. j])
				j = j + 1
			end
		end
		i = i + 1
	end
	result = gsub(result, "separator", match(result, "formerly") and ";" or ",")
	
	return zh_format("(") .. result .. zh_format(")")
end

return M