본문으로 이동

모듈:columns

위키낱말사전, 말과 글의 누리

함수

[편집]

export.format_item

[편집]

function export.format_item(item, args, face)

이 함수에는 설명문서가 존재하지 않습니다. 함수에 대한 사용법과 입출력, 유사한 함수와의 차이점을 다른 사용자들이 참고할 수 있도록 추가하거나, 함수 목록에서 제거하기 위해 지역 함수로 변경하세요.

export.construct_old_style_header

[편집]

function export.construct_old_style_header(header, horiz)

이 함수에는 설명문서가 존재하지 않습니다. 함수에 대한 사용법과 입출력, 유사한 함수와의 차이점을 다른 사용자들이 참고할 수 있도록 추가하거나, 함수 목록에서 제거하기 위해 지역 함수로 변경하세요.

export.make_sortkey

[편집]

function export.make_sortkey(frame)

여러 정렬 키를 동시에 생성하기 위한 봇 호출 가능 함수입니다. |1=은 언어 코드를 포함하고, 나머지 숫자 매개변수는 "봇 URL 인코딩"된 문자열을 포함하며, 이들의 정렬 키가 계산되어 JSON 배열로 반환됩니다. 여기서 "봇 URL 인코딩"은 6개의 문자 `| = & %`를 URL 인코딩된 표현(각각 `%7B %7C %7D %3D %26 %25`)으로 변환해야 함을 의미하며, 정렬 키를 계산하기 전에 적절하게 디코딩됩니다.

export.create_list

[편집]

function export.create_list(args)

HTML을 사용하여 항목 목록의 형식을 지정합니다. args는 추가할 항목과 관련 속성을 지정하는 객체이며 다음 필드를 가집니다:

  • content: 형식화할 항목의 목록. 항목의 형식은 아래를 참조하십시오.
  • lang: content의 항목이 문자열인 경우 형식화할 항목의 언어 객체.
  • sc: content의 항목이 문자열인 경우 형식화할 항목의 문자 객체.
  • raw: true이면, 접거나 단으로 나누지 않고 목록을 그대로 반환합니다.
  • class: 주변
    의 CSS 클래스.
  • column_count: 목록을 형식화할 단의 수.
  • alphabetize: true이면, 표의 항목을 정렬합니다.
  • collapse: true이면, 표를 기본적으로 부분적으로 접히게 하고 하단에 "더 보기" 버튼을 표시합니다.
  • toggle_category: 접을 수 있는 요소를 그룹화하는 data-toggle-category 속성의 값.
  • header: 지정된 경우, 출력 앞에 추가할 위키코드.
  • title_new_style: true이면, 머리글이 제목으로 처리되어 새 스타일로 표시됩니다. horiz가 nil이 아니면 무시됩니다.
  • subitem_separator: 한 줄에 여러 하위 항목이 있을 때 하위 항목 사이에 사용되는 구분자 (하위 항목 자체에서 separator 필드를 사용하여 지정하지 않은 경우). 기본값은 ", ".
  • keepfirst: > 0이면, 최상위 수준의 시작 부분에서 이 수만큼의 행을 정렬하지 않은 상태로 유지합니다.
  • keeplast: > 0이면, 최상위 수준의 끝에서 이 수만큼의 행을 정렬하지 않은 상태로 유지합니다.

content의 각 항목은 다음 형식 중 하나입니다:

  • 문자열. 이것은 호환성을 위한 것이며 새 호출자는 사용해서는 안 됩니다.
  • 모듈:links의 full_link()에서 예상하는 형식의 항목을 설명하는 객체. 왼쪽 또는 오른쪽 한정어, 왼쪽 또는 오른쪽 레이블 또는 참조를 가질 수도 있습니다.
  • 쉼표나 다른 구분자로 구분하여 나란히 표시되는 하위 항목 목록을 설명하는 객체. 이 형식은 하위 항목 목록을 지정하는 terms 키의 존재로 식별됩니다. 각 하위 항목은 최상위 단일 항목과 동일한 형식이지만, 각 항목 앞에 표시할 구분자를 지정하는 separator 필드도 있어야 합니다(일반적으로 첫 항목 앞에는 빈 문자열).

export.create_table

[편집]

function export.create_table(...)

이 함수에는 설명문서가 존재하지 않습니다. 함수에 대한 사용법과 입출력, 유사한 함수와의 차이점을 다른 사용자들이 참고할 수 있도록 추가하거나, 함수 목록에서 제거하기 위해 지역 함수로 변경하세요.

export.display_from

[편집]

function export.display_from(frame_args, parent_args, frame)

이 함수에는 설명문서가 존재하지 않습니다. 함수에 대한 사용법과 입출력, 유사한 함수와의 차이점을 다른 사용자들이 참고할 수 있도록 추가하거나, 함수 목록에서 제거하기 위해 지역 함수로 변경하세요.

export.handle_display_from_or_topic_list

[편집]

function export.handle_display_from_or_topic_list(iargs, raw_item_args, topic_list_data)

`display_from()` [{{col}} 및 변형의 내부 진입점, 원래 `display()`를 통해 들어옴]과 Module:topic list를 통해 호출되는 일반적인 (단 지향) 주제 목록을 구현합니다. iargs{{col}}의 호출 인수이고, raw_item_args{{col}}의 사용자가 지정한 틀 인수에 해당하는 각 행의 값과 기타 속성을 지정하는 인수입니다. Module:topic list의 `show()`는 보통 주제 목록 틀에 의해 직접 호출되며, 그 호출 인수는 raw_item_args를 통해 전달되고 {{col}}의 틀 인수와 유사합니다. 주제 목록 호출의 iargs는 하드코딩되어 있으며, 주제 목록 틀에 대한 틀 인수는 Module:topic list 자체에서 처리됩니다. 현재 주제 목록 처리는 결합도를 줄이고 주제 목록 관련 코드를 Module:topic list에 유지하기 위해 topic_list_data의 콜백을 통해 거의 전적으로 구현되지만(주제 목록이 아닌 {{col}}을 처리하는 경우 nil), 결합도는 여전히 너무 높다고 생각됩니다. 아마도 제어 구조를 반대로 하고 다음 함수를 하위 함수로 분할하여 {{col}} 및/또는 Module:topic list에서 필요에 따라 호출해야 합니다.

export.display

[편집]

function export.display(frame)

이 함수에는 설명문서가 존재하지 않습니다. 함수에 대한 사용법과 입출력, 유사한 함수와의 차이점을 다른 사용자들이 참고할 수 있도록 추가하거나, 함수 목록에서 제거하기 위해 지역 함수로 변경하세요.


local export = {}

local collation_module = "Module:collation"
local debug_track_module = "Module:debug/track"
local headword_data_module = "Module:headword/data"
local JSON_module = "Module:JSON"
local languages_module = "Module:languages"
local links_module = "Module:also/link"
local pages_module = "Module:pages"
local parameter_utilities_module = "Module:parameter utilities"
local parameters_module = "Module:parameters"
local parse_utilities_module = "Module:parse utilities"
local pron_qualifier_module = "Module:pron qualifier"
local qualifier_module = "Module:qualifier"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local templatestyles_module = "Module:TemplateStyles"
local utilities_module = "Module:utilities"
local yesno_module = "Module:yesno"

local m_str_utils = require(string_utilities_module)

local concat = table.concat
local html = mw.html.create
local is_substing = mw.isSubsting
local insert = table.insert
local rmatch = m_str_utils.match
local remove = table.remove
local sub = string.sub
local trim = m_str_utils.trim
local u = m_str_utils.char
local dump = mw.dumpObject


local function track(page)
    require(debug_track_module)("columns/" .. page)
    return true
end

local function deepEquals(...)
    deepEquals = require(table_module).deepEquals
    return deepEquals(...)
end

local function term_already_linked(term)
	return term == "?" or -- 알 수 없는 낱말을 나타냄
		-- [[Module:parse utilities]]를 불필요하게 불러오지 않기 위한 최적화
		(term:find("[<{]") and require(parse_utilities_module).term_already_linked(term))
end

local function convert_delimiter_to_separator(item, itemind, args)
	if itemind == 1 then
		item.separator = nil
	elseif item.delimiter == " " then
		item.separator = args.space_delim
	elseif item.delimiter == "~" then
		item.separator = args.tilde_delim
	else
		item.separator = args.comma_delim
	end
end

local function get_horizontal_separator(args_horiz, embedded_comma)
	return args_horiz == "bullet" and " · " or embedded_comma and "; " or ", "
end


-- [[분류:중복된 위키링크가 있는 한국어 링크]]와 같은 분류에서 위양성을 억제하여
-- 사용자가 이를 "수정"하려는 것을 방지합니다. [[Micros~1]]처럼 내장된 ~ 기호나
-- [[1,6-Cleves acid]]처럼 공백이 뒤따르지 않는 쉼표가 포함된 용어는
-- 물결표나 쉼표가 구분자로 해석되지 않도록 링크로 감싸야 합니다.
local function suppress_redundant_wikilink_cat(term, alt)
	return term:find("~") or term:find(",%S")
end

local function full_link_and_track_self_links(item, face, nochecktr)
	if item.term then
		local pagename = mw.loadData(headword_data_module).pagename
		local term_is_pagename = item.term == pagename
		local term_contains_pagename = item.term:find("%[%[" .. m_str_utils.pattern_escape(pagename) .. "[|%]]")
		if term_is_pagename or term_contains_pagename then
			local current_L2 = require(pages_module).get_current_L2()
			if current_L2 then
				local current_L2_lang = require(languages_module).getByCanonicalName(current_L2)
				if current_L2_lang and current_L2_lang:getCode() == item.lang:getCode() then
					if term_is_pagename then
						track("term-is-pagename")
					else
						track("term-contains-pagename")
					end
				end
			end
		end
	end

	item.suppress_redundant_wikilink_cat = suppress_redundant_wikilink_cat
	item.never_call_transliteration_module = nochecktr
	return require(links_module).full_link(item, face)
end

local function format_subitem(subitem, lang, face, compute_embedded_comma, nochecktr)
	local embedded_comma = false
	local text
	if subitem.term and term_already_linked(subitem.term) then
		text = subitem.term
		if compute_embedded_comma then
			embedded_comma = not not require(utilities_module).get_plaintext(text):find(",")
		end
	else
		text = full_link_and_track_self_links(subitem, face, nochecktr)
		if compute_embedded_comma then
			-- 한정어, 레이블, 참조 텍스트는 괄호 안에 있거나 다른 곳에 표시되므로 쉼표를 확인하지 않습니다.
			local subitem_plaintext = subitem.alt or subitem.term
			if subitem_plaintext then
				embedded_comma = not not subitem_plaintext:find(",")
			end
		end
	end
-- full_link()의 "show qualifiers" 플래그를 사용할 수 있지만, term_already_linked()일 때는 사용할 수 없습니다.
	if subitem.q and subitem.q[1] or subitem.qq and subitem.qq[1] or subitem.l and subitem.l[1] or
		subitem.ll and subitem.ll[1] or subitem.refs and subitem.refs[1] then
		text = require(pron_qualifier_module).format_qualifiers {
			lang = subitem.lang or args.lang,
			text = text,
			q = subitem.q,
			qq = subitem.qq,
			l = subitem.l,
			ll = subitem.ll,
			refs = subitem.refs,
		}
	end
	return text, embedded_comma
end

function export.format_item(item, args, face)
	local compute_embedded_comma = args.horiz == "comma"
	local embedded_comma = false
	local nochecktr = args.noautotr
	if type(item) == "table" then
		if item.terms then
			local parts = {}
			local is_first = true
			for _, subitem in ipairs(item.terms) do
				if subitem == false then
					-- 생략된 하위 항목, 아무것도 하지 않음
				else
					local separator = subitem.separator or not is_first and (args.subitem_separator or ", ")
					if separator then
						if compute_embedded_comma then
							embedded_comma = embedded_comma or not not separator:find(",")
						end
						insert(parts, separator)
					end
					local formatted, this_embedded_comma = format_subitem(subitem, args.lang, face,
						compute_embedded_comma, nochecktr)
					embedded_comma = embedded_comma or this_embedded_comma
					insert(parts, formatted)
					is_first = false
				end
			end
			return concat(parts), embedded_comma
		else
			return format_subitem(item, args.lang, face, compute_embedded_comma, nochecktr)
		end
	else
		if compute_embedded_comma then
			embedded_comma = not not require(utilities_module).get_plaintext(item):find(",")
		end
		if args.lang and not term_already_linked(item) then
			return full_link_and_track_self_links({lang = args.lang, term = item, sc = args.sc}, face, nochecktr), embedded_comma
		else
			return item, embedded_comma
		end
	end
end

function export.construct_old_style_header(header, horiz)
	local old_style_header
	local function ib_colon()
		return tostring(html("span"):addClass("ib-colon"):addClass("ib-content"):wikitext(":"))
	end
	if horiz then
		old_style_header = require(qualifier_module).format_qualifiers {
			qualifiers = header,
			open = false,
			close = false,
		} .. ib_colon() ..  " "
	else
		old_style_header = require(qualifier_module).format_qualifiers {
			qualifiers = header
		} .. ib_colon()
		old_style_header = tostring(html("div"):wikitext(old_style_header))
	end
	return old_style_header
end

-- 단일 용어의 정렬 기준을 구성합니다. 편법으로, 부록을 일반 문서 항목 뒤에 정렬합니다.
local function term_sortbase(val)
	if not val then
		-- 이것은 보통 발생해서는 안 됩니다.
		return u(0x10FFFF)
	elseif val:find("^%[*부록:") then
		return u(0x10FFFE) .. val
	else
		return val
	end
end

-- 표시 형식을 우선적으로 사용하고, 그렇지 않으면 용어 자체를 사용하여 단일 항목의 정렬 기준을 구성합니다.
-- 편법으로, 부록을 일반 문서 항목 뒤에 정렬합니다.
local function item_sortbase(item)
	return term_sortbase(item.alt or item.term)
end

local function make_sortbase(item)
	if item == false then
		return "*" -- 중요하지 않음, create_list()에서 생략됨
	elseif type(item) == "table" then
		if item.terms then
			-- 단일 낱말의 일반적인 경우에 대해 최적화
			if item.terms[2] then
				local parts = {}
				-- 여러 낱말
				local first = true
				for _, subitem in ipairs(item.terms) do
					if subitem ~= false then
						if not first then
							insert(parts, ", ")
						end
						insert(parts, item_sortbase(subitem))
						first = false
					end
				end
				if parts[1] then
					return concat(parts)
				end
			else
				local subitem = item.terms[1]
				if subitem ~= false then
					return item_sortbase(subitem)
				end
			end
			return "*" -- 중요하지 않음, 전체 그룹이 create_list()에서 생략됨
		else
			return item_sortbase(item)
		end
	else
		return item
	end
end

local function make_node_sortbase(node)
	return make_sortbase(node.item)
end

-- `list`의 하위 목록을 제자리에서 정렬하되, 처음 `keepfirst`개와 마지막 `keeplast`개 항목은 고정시킵니다.
-- `lang`은 항목의 언어이며 `make_sortbase`는 적절한 정렬 기준을 생성합니다.
local function sort_sublist(list, lang, make_sortbase, keepfirst, keeplast)
	if keepfirst == 0 and keeplast == 0 then
		require(collation_module).sort(list, lang, make_sortbase)
	else
		local sublist = {}
		for i = keepfirst + 1, #list - keeplast do
			sublist[i - keepfirst] = list[i]
		end
		require(collation_module).sort(sublist, lang, make_sortbase)
		for i = keepfirst + 1, #list - keeplast do
			list[i] = sublist[i - keepfirst]
		end
	end
end

-- 틀 구분자로 사용되는 문자(왼쪽 및 오른쪽 중괄호, 수직 막대, 등호 및 이스케이프 문자인 백분율 기호)만 URL 인코딩합니다.
local function bot_url_encode(txt)
	return (txt:gsub("[%%|{}=&]",
		{["%"] = "%25", ["|"] =  "%7C", ["{"] = "%7B", ["}"] = "%7D", ["="] = "%3D", ["&"] = "%26"}))
end

-- bot_url_encode()의 동작을 되돌립니다.
local function bot_url_decode(txt)
	return (txt:gsub("%%7([BCD])", {B = "{", C = "|", D = "}"}):gsub("%%3D", "="):gsub("%%26", "&"):gsub("%%25", "%%"))
end

--[==[
여러 정렬 키를 동시에 생성하기 위한 봇 호출 가능 함수입니다. {{para|1}}은 언어 코드를 포함하고,
나머지 숫자 매개변수는 "봇 URL 인코딩"된 문자열을 포함하며, 이들의 정렬 키가 계산되어 JSON 배열로 반환됩니다.
여기서 "봇 URL 인코딩"은 6개의 문자 `{ | } = & %`를 URL 인코딩된 표현(각각 `%7B %7C %7D %3D %26 %25`)으로
변환해야 함을 의미하며, 정렬 키를 계산하기 전에 적절하게 디코딩됩니다.
]==]
function export.make_sortkey(frame)
	local iparams = {
		[1] = {type = "language"},
		[2] = {list = true},
	}
	local iargs = require(parameters_module).process(frame.args, iparams)
	local make_sortkey = require(collation_module).make_lang_sortkey_function(iargs[1], term_sortbase)
	local retval = {}
	for _, arg in ipairs(iargs[2]) do
		arg = bot_url_decode(arg)
		insert(retval, make_sortkey(arg))
	end
	return require(JSON_module).toJSON(retval)
end


local large_text_scripts = {
	["Arab"] = true,
	["Beng"] = true,
	["Deva"] = true,
	["Gujr"] = true,
	["Guru"] = true,
	["Hebr"] = true,
	["Khmr"] = true,
	["Knda"] = true,
	["Laoo"] = true,
	["Mlym"] = true,
	["Mong"] = true,
	["Mymr"] = true,
	["Orya"] = true,
	["Sinh"] = true,
	["Syrc"] = true,
	["Taml"] = true,
	["Telu"] = true,
	["Tfng"] = true,
	["Thai"] = true,
	["Tibt"] = true,
}

--[==[
HTML을 사용하여 항목 목록의 형식을 지정합니다. `args`는 추가할 항목과 관련 속성을 지정하는 객체이며 다음 필드를 가집니다:
* `content`: 형식화할 항목의 목록. 항목의 형식은 아래를 참조하십시오.
* `lang`: `content`의 항목이 문자열인 경우 형식화할 항목의 언어 객체.
* `sc`: `content`의 항목이 문자열인 경우 형식화할 항목의 문자 객체.
* `raw`: true이면, 접거나 단으로 나누지 않고 목록을 그대로 반환합니다.
* `class`: 주변 <div>의 CSS 클래스.
* `column_count`: 목록을 형식화할 단의 수.
* `alphabetize`: true이면, 표의 항목을 정렬합니다.
* `collapse`: true이면, 표를 기본적으로 부분적으로 접히게 하고 하단에 "더 보기" 버튼을 표시합니다.
* `toggle_category`: 접을 수 있는 요소를 그룹화하는 `data-toggle-category` 속성의 값.
* `header`: 지정된 경우, 출력 앞에 추가할 위키코드.
* `title_new_style`: true이면, 머리글이 제목으로 처리되어 새 스타일로 표시됩니다. `horiz`가 nil이 아니면 무시됩니다.
* `subitem_separator`: 한 줄에 여러 하위 항목이 있을 때 하위 항목 사이에 사용되는 구분자 (하위 항목 자체에서 `separator` 필드를 사용하여 지정하지 않은 경우). 기본값은 {", "}.
* `keepfirst`: > 0이면, 최상위 수준의 시작 부분에서 이 수만큼의 행을 정렬하지 않은 상태로 유지합니다.
* `keeplast`: > 0이면, 최상위 수준의 끝에서 이 수만큼의 행을 정렬하지 않은 상태로 유지합니다.

`content`의 각 항목은 다음 형식 중 하나입니다:
* 문자열. 이것은 호환성을 위한 것이며 새 호출자는 사용해서는 안 됩니다.
* [[모듈:links]]의 full_link()에서 예상하는 형식의 항목을 설명하는 객체. 왼쪽 또는 오른쪽 한정어, 왼쪽 또는 오른쪽 레이블 또는 참조를 가질 수도 있습니다.
* 쉼표나 다른 구분자로 구분하여 나란히 표시되는 하위 항목 목록을 설명하는 객체.
  이 형식은 하위 항목 목록을 지정하는 `terms` 키의 존재로 식별됩니다. 각 하위 항목은 최상위 단일 항목과 동일한 형식이지만,
  각 항목 앞에 표시할 구분자를 지정하는 `separator` 필드도 있어야 합니다(일반적으로 첫 항목 앞에는 빈 문자열).
]==]
function export.create_list(args)
	if type(args) ~= "table" then
		error("테이블을 예상했으나 다음을 받음: " .. type(args))
	end

	local column_count = args.column_count or 1
	local toggle_category = args.toggle_category or "파생어"
	local keepfirst = args.keepfirst or 0
	local keeplast = args.keeplast or 0
	if keepfirst > 0 then
		track("keepfirst")
	end
	if keeplast > 0 then
		track("keeplast")
	end

	-- 이전 스타일 머리글 구성
	local old_style_header = nil
	if args.header and (args.horiz or not args.title_new_style) then
		old_style_header = export.construct_old_style_header(args.header, args.horiz)
	end
	if args.horiz then
		old_style_header = "* " .. (old_style_header or "")
	end

	local list

	local any_extra_indented_item = false
	for _, item in ipairs(args.content) do
		if item == false then
			-- 아무것도 하지 않음
		elseif type(item) == "table" and item.extra_indent and item.extra_indent > 0 then
			any_extra_indented_item = true
			break
		end
	end

	-- 추가 들여쓰기 항목이 있는 경우, 항목을 중첩 구조로 변환합니다. 이는 정렬과 HTML로 변환하는 데 모두 필요합니다.
	if any_extra_indented_item then
		local function make_node(item)
			return {
				item = item
			}
		end
		local root_node = make_node(nil)
		local node_stack = {root_node}
		local last_indent = 0
		local function append_subnode(node, subnode)
			if not node.subnodes then
				node.subnodes = {}
			end
			insert(node.subnodes, subnode)
		end
		for i, item in ipairs(args.content) do
			if item == false then
				-- 아무것도 하지 않음
			else
				local this_indent
				if type(item) ~= "table" then
					this_indent = 1
				else
					this_indent = (item.extra_indent or 0) + 1
				end
				local node = make_node(item)
				if this_indent == last_indent then
					append_subnode(node_stack[#node_stack], node)
				elseif this_indent > last_indent + 1 then
					error(("항목 #%s (%s)의 들여쓰기는 %s이며, 이전 항목의 들여쓰기 %s보다 1 이상 큽니다."):format(
						i, make_sortbase(item), this_indent, last_indent))
				elseif this_indent > last_indent then
					-- 한 수준 위 하위 목록의 마지막 항목에 새 하위 목록을 연결합니다. 
					-- 최상위 노드(last_indent == 0)는 특별히 처리해야 합니다.
					if last_indent > 0 then
						local subnodes = node_stack[#node_stack].subnodes
						if not subnodes then
							error(("내부 오류: 첫 항목이 아니며 이전 레벨 %s에 하위 노드가 없습니다: %s"):format(
								#node_stack, dump(node_stack)))
						end
						insert(node_stack, subnodes[#subnodes])
					end
					append_subnode(node_stack[#node_stack], node)
					last_indent = this_indent
				else
					while last_indent > this_indent do
						local finished_node = table.remove(node_stack)
						if args.alphabetize then
							require(collation_module).sort(finished_node.subnodes, args.lang, make_node_sortbase)
						end
						last_indent = last_indent - 1
					end
					append_subnode(node_stack[#node_stack], node)
				end
			end
		end
		if args.alphabetize then
			while node_stack[1] do
				local finished_node = table.remove(node_stack)
				if node_stack[1] then
					-- 최상위 노드가 아닌 것을 정렬하고 있습니다.
					require(collation_module).sort(finished_node.subnodes, args.lang, make_node_sortbase)
				else
					-- 최상위 노드를 정렬하고 있습니다. `keepfirst`와 `keeplast`를 존중합니다.
					sort_sublist(finished_node.subnodes, args.lang, make_node_sortbase, keepfirst, keeplast)
				end
			end
		end

		local function format_node(node, depth)
			local sublist
			local embedded_comma = false
			if node.subnodes then
				if args.horiz then
					sublist = {}
				else
					sublist = html("ul")
				end
				local prevnode = nil
				for _, subnode in ipairs(node.subnodes) do
					local thisnode, this_embedded_comma = format_node(subnode, depth + 1)
					embedded_comma = embedded_comma or this_embedded_comma
					if not prevnode or not args.alphabetize or not deepEquals(prevnode, thisnode) then
						if args.horiz then
							table.insert(sublist, thisnode)
						else
							sublist = sublist:node(thisnode)
						end
						prevnode = thisnode
					end
				end
				if args.horiz then
					sublist = table.concat(sublist, get_horizontal_separator(args.horiz, embedded_comma))
				end
			end
			if not node.item then
				-- 최상위에 있습니다.
				return sublist, embedded_comma
			end
			local formatted, listitem
			-- 괄호 또는 대괄호 안의 하위 항목에서 내장된 쉼표를 무시합니다.
			formatted, embedded_comma = export.format_item(node.item, args)
			if args.horiz then
				listitem = formatted
				if sublist then
					-- 첫 번째, 세 번째, 다섯 번째 등 하위 목록에는 괄호를 사용하고 나머지는 대괄호를 사용합니다.
					if depth % 2 == 1 then
						listitem = ("%s (%s)"):format(listitem, sublist)
					else
						listitem = ("%s [%s]"):format(listitem, sublist)
					end
				end
			else
				listitem = html("li"):wikitext(formatted)
				if sublist then
					listitem = listitem:node(sublist)
				end
			end
			return listitem, embedded_comma
		end

		list = format_node(root_node, 0)
	else
		if args.alphabetize then
			sort_sublist(args.content, args.lang, make_sortbase, keepfirst, keeplast)
		end
		if args.horiz then
			list = {}
		else
			list = html("ul")
		end
		local previtem = nil
		local embedded_comma = false
		for _, item in ipairs(args.content) do
			if item == false then
				-- 생략된 항목, 아무것도 하지 않음
			else
				local thisitem, this_embedded_comma = export.format_item(item, args)
				embedded_comma = embedded_comma or this_embedded_comma
				if not previtem or not args.alphabetize or previtem ~= thisitem then
					if args.horiz then
						table.insert(list, thisitem)
					else
						list = list:node(html("li"):wikitext(thisitem))
					end
					previtem = thisitem
				end
			end
		end
		if args.horiz then
			list = table.concat(list, get_horizontal_separator(args.horiz, embedded_comma))
		end
	end

	local output
	if args.horiz then
		output = list
	else
		output = html("div"):addClass("term-list"):node(list)

		if args.class then
			output:addClass(args.class)
		end

		if not args.raw then
			output:addClass("ul-column-count")
				:attr("data-column-count", column_count)

			if args.collapse then
				output = html("div")
					:node(output)
					:addClass("list-switcher")
					:attr("data-toggle-category", toggle_category)

				-- 큰 텍스트를 사용하는 스크립트를 식별하고
				-- 틀을 더 크게 만들기 위한 특수 CSS 클래스를 제공합니다.
				local sc = args.sc
				if sc == nil then
					local scripts = args.lang:getScripts()
					if #scripts > 0 then
						sc = scripts[1]
					end
				end
				if sc ~= nil then
					local scriptcode = sc:getParentCode()
					if scriptcode == "top" then
						scriptcode = sc:getCode()
					end
					if large_text_scripts[scriptcode] then
						output:addClass("list-switcher-large-text")
					end
				end
			end
		end

		if args.collapse or args.title_new_style then
			-- 떠다니는 요소의 간섭을 막기 위해 래퍼로 감쌉니다.
			local list_switcher_wrapper = html("div")
				:addClass("list-switcher-wrapper")
				
			if args.title_new_style then
				list_switcher_wrapper
					:node(
					html("div")
						:addClass("list-switcher-header")
						:wikitext(args.header)
				)
			end
			
			list_switcher_wrapper:node(output)
			output = list_switcher_wrapper
		end

		output = tostring(output)
	end
	
	local templatestyles = require(templatestyles_module)("Module:list/styles.css")
	return templatestyles .. (old_style_header or "") .. output
end


-- This function is for compatibility with earlier version of [[Module:columns]]
-- (now found in [[Module:columns/old]]).
function export.create_table(...)
	-- Earlier arguments to create_table:
	-- n_columns, content, alphabetize, bg, collapse, class, title, column_width, line_start, lang
	local args = {}
	args.column_count, args.content, args.alphabetize,
		args.collapse, args.class, args.header, args.column_width,
		args.line_start, args.lang = ...

	return export.create_list(args)
end


function export.display_from(frame_args, parent_args, frame)
	local boolean = {type = "boolean"}
	local iparams = {
		["class"] = true,
		-- 자동 접기 기본값. 틀의 |collapse= 매개변수로 덮어쓸 수 있습니다.
		["collapse"] = boolean,
		-- 지정된 경우, 단의 수를 지정하며 틀에 단 매개변수가 없습니다.
		-- 그렇지 않으면 단 매개변수는 |n=입니다.
		["columns"] = {type = "number"},
		-- 지정된 경우, 기본 언어 코드를 지정하며, 틀의 |lang=으로 덮어쓸 수 있습니다.
		-- 그렇지 않으면 언어 코드 매개변수는 필수이며 보통 |1=에 있지만,
		-- 호환성을 위해 |lang=으로 지정할 수 있습니다(이는 폐기 예정 처리로 이어짐).
		["lang"] = {type = "language"},
		-- 자동 정렬 기본값. 틀의 |sort= 매개변수로 덮어쓸 수 있습니다.
		["sort"] = boolean,
		["toggle_category"] = true,
		-- 다단 목록으로 형식화하는 데 필요한 최소 행 수. 이보다 적으면 목록이 "raw"로 표시됩니다.
		-- (단 없음, 접기 없음).
		["minrows"] = {type = "number", default = 5},
		["noautotr"] = boolean,
	}

	local iargs = require(parameters_module).process(frame_args, iparams)

	local langcode_in_lang = iargs.lang or parent_args.lang
	local lang_param = langcode_in_lang and "lang" or 1
	local deprecated = not iargs.lang and langcode_in_lang

	local ret = export.handle_display_from_or_topic_list(iargs, parent_args, nil)

	return deprecated and frame:expandTemplate{title = "check deprecated lang param usage",
		args = {ret, lang = args[lang_param]}} or ret
end


--[==[
`display_from()` [{{tl|col}} 및 변형의 내부 진입점, 원래 `display()`를 통해 들어옴]과
[[Module:topic list]]를 통해 호출되는 일반적인 (단 지향) 주제 목록을 구현합니다.
`iargs`는 {{tl|col}}의 호출 인수이고, `raw_item_args`는 {{tl|col}}의 사용자가 지정한 틀 인수에 해당하는
각 행의 값과 기타 속성을 지정하는 인수입니다. [[Module:topic list]]의 `show()`는 보통 주제 목록 틀에 의해
직접 호출되며, 그 호출 인수는 `raw_item_args`를 통해 전달되고 {{tl|col}}의 틀 인수와 유사합니다.
주제 목록 호출의 `iargs`는 하드코딩되어 있으며, 주제 목록 틀에 대한 틀 인수는 [[Module:topic list]] 자체에서 처리됩니다.
현재 주제 목록 처리는 결합도를 줄이고 주제 목록 관련 코드를 [[Module:topic list]]에 유지하기 위해
`topic_list_data`의 콜백을 통해 거의 전적으로 구현되지만(주제 목록이 아닌 {{tl|col}}을 처리하는 경우 nil),
결합도는 여전히 너무 높다고 생각됩니다. 아마도 제어 구조를 반대로 하고 다음 함수를 하위 함수로 분할하여
{{tl|col}} 및/또는 [[Module:topic list]]에서 필요에 따라 호출해야 합니다.
]==]
function export.handle_display_from_or_topic_list(iargs, raw_item_args, topic_list_data)
	local boolean = {type = "boolean"}
	local langcode_in_lang = iargs.lang or raw_item_args.lang
	local lang_param = langcode_in_lang and "lang" or 1
	local first_content_param = langcode_in_lang and 1 or 2

	local params = {
		[lang_param] = {required = not iargs.lang, type = "language",
			template_default = not iargs.lang and "und" or nil},
		["n"] = not iargs.columns and {type = "number"} or nil,
		[first_content_param] = {list = true, allow_holes = true},

		["title"] = {},
		["collapse"] = boolean,
		["sort"] = boolean,
		["sc"] = {type = "script"},
		-- [[Module:saurus]]에서 호출할 때 사용되어 동의어/반의어를 표시하는 페이지가
		-- 목록에 나타나지 않도록 함
		["omit"] = {list = true},
		["keepfirst"] = {type = "number", default = 0},
		["keeplast"] = {type = "number", default = 0},
		["horiz"] = {},
		["notr"] = boolean,
		["noautotr"] = boolean,
		["allow_space_delim"] = boolean,
		["tilde_delim"] = {},
		["space_delim"] = {},
		["comma_delim"] = {},
	}

	if topic_list_data then
		topic_list_data.add_topic_list_params(params)
	end

	local m_param_utils = require(parameter_utilities_module)

	local param_mods = m_param_utils.construct_param_mods {
		{default = true, require_index = true},
		{group = "link"}, -- sc는 separate_no_index = true; 그것이 유일함
		-- 단 목록 표시에 대해 전체적인 l=, ll=, q= 또는 qq= 매개변수를 갖는 것은 의미가 없음.
		{group = {"ref", "l", "q"}, require_index = true},
	}

	m_param_utils.augment_params_with_modifiers(params, param_mods)
	local processed_args = require(parameters_module).process(raw_item_args, params)
	local horiz = processed_args.horiz
	if horiz and horiz ~= "comma" and horiz ~= "bullet" then
		horiz = require(yesno_module)(horiz)
		if horiz == nil then
			error(("인식할 수 없는 |horiz=%s 값입니다. 'comma', 'bullet' 또는 'yes'나 '1'('bullet'과 동일), 'no'나 '0'과 같은 불리언 값이어야 합니다."):format(processed_args.horiz))
		end
		if horiz == true then
			horiz = "bullet"
		end
		processed_args.horiz = horiz
	end
		
	-- 기본 인수 값이 지정된 경우, `raw_item_args`에서 호출자 지정 인수를 파싱한 후 설정합니다.
	if topic_list_data then
		topic_list_data.set_default_arguments(processed_args)
	end

	-- 이제 horiz 설정 여부에 따라 다양한 구분자의 기본값을 설정합니다.
	-- `default_props`에 지정된 기본값이 이를 덮어쓰도록 하기 위해 이 기본값을 위의 `local params`에서
	-- (horiz=에 대한 의존성과 무관하게) 설정할 수 없습니다.
	if not processed_args.tilde_delim then
		local tilde_with_abbr = '<abbr title="near equivalent">~</abbr>'
		processed_args.tilde_delim = processed_args.horiz and tilde_with_abbr or " " .. tilde_with_abbr .. " "
	end
	if not processed_args.space_delim then
		processed_args.space_delim = "&nbsp;"
	end
	if not processed_args.comma_delim then
		processed_args.comma_delim = processed_args.horiz and "/" or ", "
	end

	-- 추가 용어 들여쓰기를 확인합니다. parse_list_with_inline_modifiers_and_separate_params()를 호출하기 전에
	-- 이 작업을 수행합니다. 때로는 공백이 구분자이며 들여쓰기의 공백이 혼동을 일으켜
	-- 구분자로 해석될 수 있기 때문입니다.
	local extra_indent_by_termno = {}
	local termargs = processed_args[first_content_param]
	for i = 1, termargs.maxindex do
		local term = termargs[i]
		if term then
			local extra_indent, actual_term = rmatch(term, "^(%*+)%s+(.-)$")
			if extra_indent then
				termargs[i] = actual_term
				extra_indent_by_termno[i] = #extra_indent
			end
		end
	end

	local groups, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
		param_mods = param_mods,
		processed_args = processed_args,
		termarg = first_content_param,
		parse_lang_prefix = true,
		allow_multiple_lang_prefixes = true,
		disallow_custom_separators = true,
		track_module = "columns",
		lang = iargs.lang or lang_param,
		sc = "sc.default",
		splitchar = processed_args.allow_space_delim and "[,~ ]" or "[,~]",
	}

	local lang = iargs.lang or args[lang_param]
	local langcode = lang:getCode()
	local fulllangcode = lang:getFullCode()
	local sc = args.sc.default

	local sort = iargs.sort
	if args.sort ~= nil then
		if not args.sort then
			track("nosort")
		end
		sort = args.sort
	else
		-- 일본어 스크립트 언어(일본어, 오키나와어, 미야코어 등)의 경우 정렬이 아직 제대로 작동하지 않으므로 비활성화합니다.
		for _, langsc in ipairs(lang:getScriptCodes()) do
			if langsc == "Jpan" then
				sort = false
				break
			end
		end
	end

	local collapse = iargs.collapse
	if args.collapse ~= nil then
		if not args.collapse then
			track("nocollapse")
		end
		collapse = args.collapse
	end

	local title = args.title
	local formatted_cats
	if topic_list_data then
		title, formatted_cats = topic_list_data.get_title_and_formatted_cats(args, lang, sc, topic_list_data)
	end

	local number_of_groups = 0
	for i, group in ipairs(groups) do
		local number_of_items = 0
		group.extra_indent = extra_indent_by_termno[group.orig_index]
		for j, item in ipairs(group.terms) do
			convert_delimiter_to_separator(item, j, args)

			if args.notr then
				item.tr = "-"
			elseif args.noautotr then
				item.tr = item.tr or "-"
			end

			-- 낱말에 대해 별도의 언어 코드가 주어진 경우, 언어 이름을 오른쪽 한정어로 표시합니다.
			-- (잠시 레이블로 만들었지만 "French"가 "France"가 되는 등 명확하지 않은 동작으로 이어짐)
			-- 그렇지 않으면 용어가 별도의 언어라는 것이 명확하지 않을 수 있습니다(예: 주 언어가 'zh'이고
			-- 용어 언어가 민난어와 같은 중국어 방언인 경우).
			-- 하지만 여러 언어의 목록에 자주 추가되는 다중 언어(Translingual) 낱말에는 이 작업을 수행하지 않습니다.
			if item.termlangs then
				local qqs = {}
				for _, termlang in ipairs(item.termlangs) do
					local termlangcode = termlang:getCode()
					if termlangcode ~= langcode and termlangcode ~= "mul" then
						insert(qqs, termlang:getCanonicalName())
					end
				end
				if item.qq then
					for _, qq in ipairs(item.qq) do
						insert(qqs, qq)
					end
				end
				item.qq = qqs
			end
			local omitted = false
			for _, omitted_item in ipairs(args.omit) do
				if omitted_item == item.term then
					omitted = true
					break
				end
			end
			if omitted then
				-- create_list()에 이 항목을 생략하라는 신호를 보냅니다
				group.terms[j] = false
			else
				number_of_items = number_of_items + 1
			end
		end
		if number_of_items == 0 then
			-- 전체 그룹을 생략합니다
			groups[i] = false
		else
			number_of_groups = number_of_groups + 1
		end
	end

	local column_count = iargs.columns or args.n
	-- FIXME: 이것은 완전히 다시 작성해야 합니다.
	if column_count == nil then
		column_count = number_of_groups <= 3 and 1 or
			number_of_groups <= 9 and 2 or
			number_of_groups <= 27 and 3 or
			number_of_groups <= 81 and 4 or
			5
	end
	local raw = number_of_groups < iargs.minrows

	local horiz_edit_button
	if topic_list_data and args.horiz then
		-- 제목에 편집 버튼 추가
		horiz_edit_button = topic_list_data.make_horiz_edit_button(topic_list_data.topic_list_template)
	end

	return export.create_list {
		column_count = column_count,
		raw = raw,
		content = groups,
		alphabetize = sort,
		header = title,
		title_new_style = (title ~= nil and title ~= ''),
		collapse = collapse,
		toggle_category = iargs.toggle_category,
		-- columns-bg (in [[MediaWiki:Gadget-Site.css]])는 배경색을 제공합니다
		-- [[Module:list/styles.css]]로 대체함 [[사:Jeebeen]]
		class = (iargs.class and iargs.class .. " columns-bg" or "columns-bg"),
		lang = lang,
		sc = sc,
		subitem_separator = ", ",
		keepfirst = args.keepfirst,
		keeplast = args.keeplast,
		horiz = args.horiz,
		noautotr = args.noautotr,
	} .. (horiz_edit_button or "") .. (formatted_cats or "")
end

function export.display(frame)
	if not is_substing() then
		return export.display_from(frame.args, frame:getParent().args, frame, false)
	end

	-- subst된 경우, 각 용어 사이에 개행 문자를 넣고, 중복된 위키링크를 제거하고,
	-- 정렬이 활성화된 경우 중복을 제거하고 용어를 정렬하여 틀을 unsubst합니다.
	local m_table = require("Module:table")
	local m_template_parser = require("Module:template parser/sandbox")

	local parent = frame:getParent()
	local elems = m_table.shallowCopy(parent.args)
	local code = remove(elems, 1)
	code = code and trim(code)
	local lang = require("Module:languages").getByCode(code, 1)

	local i = 1
	while true do
		local elem = elems[i]
		while elem do
			elem = trim(elem, "%s")
			if elem ~= "" then
				break
			end
			remove(elems, i)
			elem = elems[i]
		end
		if not elem then
			break
		elseif not ( -- 중복된 위키링크를 제거합니다.
			not elem:match("^()%[%[") or
			elem:find("[[", 3, true) or
			elem:find("]]", 3, true) ~= #elem - 1 or
			elem:find("|", 3, true)
		) then
			elem = sub(elem, 3, -3)
			elem = trim(elem, "%s")
		end
		elems[i] = elem .. "\n"
		i = i + 1
	end

	-- 정렬이 활성화된 경우, 중복을 제거한 다음 요소를 정렬합니다.
	if require("Module:yesno")(frame.args.sort) then
		elems = m_table.removeDuplicates(elems)
		require("Module:collation").sort(elems, lang)
	end

	-- 언어 코드를 다시 추가합니다.
	insert(elems, 1, code .. "\n")

	-- TODO: 숫자 없는 매개변수를 1 다음, 2 앞에 배치합니다.
	local template = m_template_parser.getTemplateInvocationName(mw.title.new(parent:getTitle()))

	return "{{" .. concat(m_template_parser.buildTemplate(template, elems), "|") .. "}}"
end

return export