Module:zh-han

local m_str_utils = require("Module:string utilities")

local codepoint = m_str_utils.codepoint local find = m_str_utils.find local get_section = require("Module:utilities").get_section local gsub = m_str_utils.gsub local sub = m_str_utils.sub

local m_links = require("Module:links") local m_script_utils = require("Module:script utilities")

local export = {}

local PAGENAME = mw.loadData("Module:headword/data").pagename

local cangjie = { A = "日", B = "月", C = "金", D = "木", E = "水", F = "火", G = "土", H = "竹", I = "戈", J = "十", K = "大", L = "中", M = "一", N = "弓", O = "人", P = "心", Q = "手", R = "口", S = "尸", T = "廿", U = "山", V = "女", W = "田", X = "難", Y = "卜", Z = "重" }

local radicals = { "一","丨","丶","丿","乙","亅", "二","亠","人","儿","入","八","冂","冖","冫","几","凵","刀","力","勹","匕","匚","匸","十","卜","卩","厂","厶","又", "口","囗","土","士","夂","夊","夕","大","女","子","宀","寸","小","尢","尸","屮","山","巛","工","己","巾","干","幺","广","廴","廾","弋","弓","彐","彡","彳", "心","戈","戶","手","支","攴","文","斗","斤","方","无","日","曰","月","木","欠","止","歹","殳","毋","比","毛","氏","气","水","火","爪","父","爻","爿","片","牙","牛","犬", "玄","玉","瓜","瓦","甘","生","用","田","疋","疒","癶","白","皮","皿","目","矛","矢","石","示","禸","禾","穴","立", "竹","米","糸","缶","网","羊","羽","老","而","耒","耳","聿","肉","臣","自","至","臼","舌","舛","舟","艮","色","艸","虍","虫","血","行","衣","襾", "見","角","言","谷","豆","豕","豸","貝","赤","走","足","身","車","辛","辰","辵","邑","酉","釆","里", "金","長","門","阜","隶","隹","雨","靑","非", "面","革","韋","韭","音","頁","風","飛","食","首","香", "馬","骨","高","髟","鬥","鬯","鬲","鬼", "魚","鳥","鹵","鹿","麥","麻", "黃","黍","黑","黹", "黽","鼎","鼓","鼠", "鼻","齊", "齒", "龍","龜", "龠" }

local simplified_radical = { ['讠']='言',['门']='門',['饣']='食',['飞']='飛',['马']='馬',['见']='見',['贝']='貝',['纟']='糸',['车']='車',['长']='長',['韦']='韋',['风']='風',['钅']='金',['鸟']='鳥',['竜']='龍',['龙']='龍',['页']='頁',['斉']='齊',['齐']='齊',['麦']='麥',['亀']='龜',['龟']='龜',['鱼']='魚',['黾']='黽',['鼡']='鼠',['歯']='齒',['齿']='齒',['卤']='鹵',['𬺞']='龜',['丬']='爿',['黒']='黑',['黄']='黃', }

local codes = { c = 'simplified Chinese', m = 'mainland China', j = 'Japanese', k = 'Korean' }

-- Letters in "as" or "sn" parameter names follow these criteria: -- There must be 1 or 2 of them. -- They must be c, m, j, or k. -- They must be in the order [cm]jk. local function validate_letters(letters) local letter_count = #letters return letter_count == 3 and (letters == 'mjk' or letters == 'cjk') or letter_count == 2 and (letters == 'jk' or letters == 'cj' or letters == 'mj') or letter_count == 1 and codes[letters] end

local function mul_link(term) return m_links.full_link({lang = require('Module:languages').getByCode('zh'), term = term.."//", tr="-"}) end

local function radical(name,number,variant) number = number or 1 local padleft = ("%03d"):format(number) local text = ' See images of Radical " .. number .. " " .. ((name and name ~= '') and PAGENAME or '※') .. "  " if name == PAGENAME or (variant and variant ~= '') then text = text .. ''	else text = text .. ''	end return text end

function export.simp(frame) local args = frame:getParent.args local trad = args[1] or '' if trad == '' then trad = mw.loadData("Module:zh/data/st")[PAGENAME] or PAGENAME end local nocap = args['nocap'] or '' local alt = args['a'] or '' local from = {args['f'] or ,args['f2'] or } local to = {args['t'] or ,args['t2'] or } if from[1] ==  and to[1] ~=  then from[1] = trad end local text = {} local result = '' result = (nocap == '' and 'S' or 's') .. 'implified from ' .. mul_link(trad) if alt ~= '' then result = result .. ' and ' .. mul_link(alt) end for i=1,2 do		if from[i] ~= '' then if to[i] == '' then table.insert(text,mul_link(from[i]) .. " → a component which cannot be displayed independently") elseif to[i] == ' ' or to[i] == ' ' then table.insert(text,'elimination of ' .. mul_link(from[i])) else table.insert(text,mul_link(from[i]) .. ' → ' .. mul_link(to[i])) end end end if #text > 0 then result = result .. ' (' .. table.concat(text,' and '):gsub('and elimination of','and') .. ')' end return result end

-- NOTE: added 2023 Nov as a sanity check for function export.cp return string.format('%.4X', codepoint(PAGENAME)) end

do local function check_translingual_only for _, sec in pairs(mw.loadData("Module:headword/data").page.L2_sections) do			if sec ~= "Translingual" then return end end require('Module:debug').track('zh-han/translingual-only character') end function export.character(frame) local args = {} for arg, val in pairs(frame:getParent.args) do -- Set empty args to nil. if val ~= '' then args[arg] = val end end if radicals[tonumber(args['rn'])] ~= (simplified_radical[args['rad']] or args['rad']) then error('Radical number (rn) and radical (rad) do not match') end local text = { insert = table.insert } local categories = { insert = table.insert } local as = tostring(tonumber(args['as'] or '-1')) if as == '0' then text:insert(radical(args['rad'], args['rn'], (args['var'] or ''))) end -- Creating headword with Module:headword ensures that page title is script-tagged with Hani (generic Han). -- This assumes that is only used in Translingual sections. local mul = require("Module:languages").getByCode("mul") local Hani = require("Module:scripts").getByCode("Hani") local sort_key = args['rad'] .. args['as'] .. PAGENAME text:insert(			require("Module:headword").full_headword{				lang = mul,				sc = Hani,				heads = { args['head'] },				categories = {},				pos_category = "symbols",				sort_key = sort_key,			}		) text:insert(" (''Kangxi radical " .. (args['rn'] or '') .. ", '' ' .. (args['rad'] or ' ') .. '+' .. as)		if args['asj'] then			text:insert(" in Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asj']) .. " in Japanese")		end		if args['asc'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asc']) .. " in simplified Chinese")		end		if args['ask'] then			text:insert(" in Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['ask']) .. " in Korean")		end		if args['asjk'] then			text:insert(" in Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asjk']) .. " in Japanese and Korean")		end		if args['asj+'] then			text:insert(" in Chinese and Korean, " .. (args['rad'] or '') .. '+' .. tonumber(args['asj+']) .. " in Japanese")		end		if args['ask+'] then			text:insert(" in Chinese and Japanese, " .. (args['rad'] or '') .. '+' .. tonumber(args['ask+']) .. " in Korean")		end		if args['asc+'] then			text:insert(" in traditional Chinese and Japanese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asc+']) .. " in simplified Chinese")		end		if args['asc++'] then			text:insert(" in traditional Chinese, Japanese and Korean, " .. (args['rad'] or '') .. '+' .. tonumber(args['asc++']) .. " in simplified Chinese")		end		if args['ascj'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['ascj']) .. " in simplified Chinese and Japanese")		end		if args['ascj+'] then			text:insert(" in traditional Chinese and Korean, " .. (args['rad'] or '') .. '+' .. tonumber(args['ascj+']) .. " in simplified Chinese and Japanese")		end		if args['asm'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asm']) .. " in mainland China")		end		if args['asmj'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asmj']) .. " in mainland China and Japanese")		end		if args['asmj+'] then			text:insert(" in traditional Chinese and Korean, " .. (args['rad'] or '') .. '+' .. tonumber(args['asmj+']) .. " in mainland China and Japanese")		end		if args['asm+'] then			text:insert(" in traditional Chinese and Japanese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asm+']) .. " in mainland China")		end		if args['asm++'] then			text:insert(" in traditional Chinese, Japanese and Korean, " .. (args['rad'] or '') .. '+' .. tonumber(args['asm++']) .. " in mainland China")		end		if args['ascjk'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['ascjk']) .. " in simplified Chinese, Japanese and Korean")		end		if args['asmjk'] then			text:insert(" in traditional Chinese, " .. (args['rad'] or '') .. '+' .. tonumber(args['asmjk']) .. " in mainland China, Japanese and Korean")		end		if args['asmjk+'] then			text:insert(" in traditional Chinese (Taiwan), " .. (args['rad'] or '') .. '+' .. tonumber(args['asmjk+']) .. " in Chinese (mainland China, Hong Kong), Japanese and Korean")		end		text:insert(", " .. (args['sn'] or '') .. " stroke")		-- To do: fix handling of multiple additional stroke numbers;		-- search query:		-- hastemplate:"Module:zh-han" insource:/\|sn[cmjk][cmjk]?\+*=[^|]+\|sn[cmjk][cmjk]?\+*=[^|]+/		if args['sn'] ~= '1' then			text:insert('s')		end		if args['snj'] then			text:insert(" in Chinese")		end		if args['snc'] then			text:insert(" in traditional Chinese")		end		if args['snk'] then			text:insert(" in Chinese")		end		if args['snjk'] then			text:insert(" in Chinese")		end		if args['snj+'] then			text:insert(" in Chinese and Korean")		end		if args['snk+'] then			text:insert(" in Chinese and Japanese")		end		if args['snc+'] then			text:insert(" in traditional Chinese and Japanese")		end		if args['snc++'] then			text:insert(" in traditional Chinese, Japanese and Korean")		end		if args['sncj'] then			text:insert(" in traditional Chinese")		end		if args['sncj+'] then text:insert(" in traditional Chinese and Korean") end if args['snm'] then text:insert(" in traditional Chinese") end if args['snmj'] then text:insert(" in traditional Chinese") end if args['snmj+'] then text:insert(" in traditional Chinese and Korean") end if args['snm+'] then text:insert(" in traditional Chinese and Japanese") end if args['snm++'] then text:insert(" in traditional Chinese, Japanese and Korean") end if args['sncjk'] then text:insert(" in traditional Chinese") end if args['snmjk'] then text:insert(" in traditional Chinese") end if args['snmjk+'] then text:insert(" in traditional Chinese (Taiwan)") end -- Find parameters specifying additional stroke numbers and add notes for -- them. for param_name, value in pairs(args) do			if type(param_name) == "string" then local letters = param_name:match("^sn(%l+)%+*$") if letters then if validate_letters(letters) then if value and value ~= '' then local label = {} for letter in letters:gmatch(".") do table.insert(label, codes[letter]) -- Already checked that letters are valid. end label = table.concat(label, " and ") text:insert(", " .. value .. " stroke") if value ~= '1' then text:insert('s') end text:insert(" in " .. label .. "") end else require("Module:debug").track('zh-han/incorrect stroke number parameter') -- return error("Unrecognized stroke number parameter name " .. param_name .. ".") end end end end if args['canj'] then local canj = args['canj'] local canj_split = mw.text.split(canj,',') for i = 1, #canj_split do				if canj_split[i]:match('^%u+$') then canj_split[i] = canj_split[i]:gsub('[%(%)]','') canj_split[i] = m_script_utils.tag_text(canj_split[i]:gsub('%u',cangjie), mul, Hani) .. ' (' .. canj_split[i] .. ')' else return error('The value of "canj" parameter is invalid.') end end text:insert(", cangjie input " .. table.concat(canj_split,' or ')) if #canj_split > 1 then categories:insert("") end end if args['four'] then local four = args['four'] local four_split = mw.text.split(four,',') for i=1,#four_split do				if not four_split[i]:match('[<>]') then four_split[i] = four_split[i]:gsub('(%d)(%d%d%d)%.?(%d?)','%1%2%3') else return error('The value of "four" parameter is invalid.') end end text:insert(", four-corner " .. table.concat(four_split,' or ')) if #four_split > 1 then categories:insert("") end end if args['ids'] then local ids = args['ids'] local ids_split = mw.text.split(ids,',') for i=1, #ids_split do				if not ids_split[i]:match('[%[%]]') then if find(ids_split[i], '^[⿲⿳](.)%1%1$') then categories:insert('') end if find(ids_split[i], '^[⿰⿱](.)%1$') then categories:insert('') end local before = {} ids_split[i] = gsub(ids_split[i], "([⺀-⻳　-〿アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヰヱヲン㇀-㇣〇一-鿿㐀-䶿﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧-﨩𠀀-𪛟𪜀-𮯠𰀀-𲎯])",						function (character)							if not before[character] then								before[character] = true								return "" .. character .. ""							else								return character							end						end) ids_split[i] = ids_split[i]:gsub("^(.-)%f[%(%z](.*)", function(m1, m2) local m1 = m_links.embedded_language_links{term = m1, lang = mul, sc = Hani} m1 = m_script_utils.tag_text(m1, mul, Hani) local letters = { G = ' G ', H = 'H ', T = ' T ', J = ' J ', K = ' K ', V = ' V ' }							return m1 .. m2:gsub(".", letters) end)				end			end			text:insert(", composition " .. table.concat(ids_split,' or '))			if #ids_split > 1 then				categories:insert("")			end		end		text:insert(')') if args['rad'] then if mw.title.getCurrentTitle.nsText == '' then categories:insert("") end else if mw.title.getCurrentTitle.nsText == '' then categories:insert("") end end local params_to_check = { "as", "rn", "sn", "ids", "four", "canj" } local sortkey = args['rad'] and "|" .. args['rad'] or "" for _, param in pairs(params_to_check) do			if not args[param] or args[param] == '' then categories:insert("") end end if type(args['sn']) == "string" and sub(args['sn'],1,1) == '0' then return error('Please remove leading zeros from the "sn" parameter.') end check_translingual_only if (get_section(mw.title.getCurrentTitle:getContent, "Translingual") or ""):match("%f[^%z\n\r]#[ \t]*%S") then categories:insert("") end return table.concat(text) .. table.concat(categories) end end

return export