모듈:quote
보이기
이 모듈에 대한 설명문서는 모듈:quote/설명문서에서 만들 수 있습니다
--[=[
이 모듈은 quote-* 계열 틀을 구현하는 함수를 포함합니다.
저자: Benwing2; Sgconlaw가 작성하고 Erutuon과 Benwing2가 일부 수정한
{{quote-meta/source}} 틀을 Lua로 변환함.
주요 인터페이스는 quote_t()입니다. 출처 표시는 source() 함수가 처리하는데,
이 함수는 자신에게 전달된 인수와 부모 틀에 전달된 인수를 모두 읽으며,
자신에게 전달된 인수가 우선합니다.
]=]
local export = {}
-- 사용하는 모든 모듈에 대한 이름 지정 상수. 샌드박스 버전을 쉽게 교체할 수 있도록 함.
local check_isxn_module = "Module:check isxn"
local debug_track_module = "Module:debug/track"
local italics_module = "Module:italics"
local labels_module = "Module:labels"
local languages_module = "Module:languages"
local languages_error_module = "Module:languages/error"
local links_module = "Module:also/link"
local number_utilities_module = "Module:number utilities"
local parameters_module = "Module:parameters"
local parse_utilities_module = "Module:parse utilities"
local qualifier_module = "Module:qualifier"
local roman_numerals_module = "Module:roman numerals"
local scribunto_module = "Module:Scribunto"
local script_utilities_module = "Module:script utilities"
local scripts_module = "Module:scripts"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local usex_module = "Module:usex"
local usex_templates_module = "Module:usex/templates"
local utilities_module = "Module:utilities"
local yesno_module = "Module:yesno"
local concat = table.concat
local insert = table.insert
local remove = table.remove
local require = require
local sort = table.sort
local u = mw.ustring.char
local ugsub = mw.ustring.gsub
local umatch = mw.ustring.match
local unpack = unpack or table.unpack -- Lua 5.2 호환성
-- 파싱 문제를 피하기 위해 HTML 엔티티를 사용 (특히 대괄호 관련)
local SEMICOLON_SPACE = "; "
local SPACE_LBRAC = " ["
local RBRAC = "]"
-- 한국어에서는 세미콜론(;)보다는 마침표(.)를 주로 사용하므로
-- 일부 상수는 추후 변경되거나 사용되지 않을 수 있습니다.
local TEMP_LT = u(0xFFF1)
local TEMP_GT = u(0xFFF2)
local TEMP_LBRAC = u(0xFFF3)
local TEMP_RBRAC = u(0xFFF4)
local TEMP_SEMICOLON = u(0xFFF5)
local function apply_subst(...)
apply_subst = require(usex_module).apply_subst
return apply_subst(...)
end
local function check_isbn(...)
check_isbn = require(check_isxn_module).check_isbn
return check_isbn(...)
end
local function check_issn(...)
check_issn = require(check_isxn_module).check_issn
return check_issn(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function embedded_language_links(...)
embedded_language_links = require(links_module).embedded_language_links
return embedded_language_links(...)
end
local function escape_wikicode(...)
escape_wikicode = require(parse_utilities_module).escape_wikicode
return escape_wikicode(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_processed_labels(...)
format_processed_labels = require(labels_module).format_processed_labels
return format_processed_labels(...)
end
local function format_qualifier(...)
format_qualifier = require(qualifier_module).format_qualifier
return format_qualifier(...)
end
local function format_usex(...)
format_usex = require(usex_module).format_usex
return format_usex(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_number(...)
get_number = require(number_utilities_module).get_number
return get_number(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function gsplit(...)
gsplit = require(string_utilities_module).gsplit
return gsplit(...)
end
local function page_should_be_ignored(...)
page_should_be_ignored = require(usex_templates_module).page_should_be_ignored
return page_should_be_ignored(...)
end
local function parse_inline_modifiers(...)
parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers
return parse_inline_modifiers(...)
end
local function parse_inline_modifiers_from_segments(...)
parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments
return parse_inline_modifiers_from_segments(...)
end
local function parse_multi_delimiter_balanced_segment_run(...)
parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run
return parse_multi_delimiter_balanced_segment_run(...)
end
local function parse_term_with_lang(...)
parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang
return parse_term_with_lang(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function process_params(...)
process_params = require(parameters_module).process
return process_params(...)
end
local function remove_links(...)
remove_links = require(links_module).remove_links
return remove_links(...)
end
local function roman_to_arabic(...)
roman_to_arabic = require(roman_numerals_module).roman_to_arabic
return roman_to_arabic(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function scribunto_parameter_key(...)
scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key
return scribunto_parameter_key(...)
end
local function serial_comma_join(...)
serial_comma_join = require(table_module).serialCommaJoin
return serial_comma_join(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function split_alternating_runs(...)
split_alternating_runs = require(parse_utilities_module).split_alternating_runs
return split_alternating_runs(...)
end
local function split_and_process_raw_labels(...)
split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels
return split_and_process_raw_labels(...)
end
local function split_on_comma(...)
split_on_comma = require(parse_utilities_module).split_on_comma
return split_on_comma(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_transcription(...)
tag_transcription = require(script_utilities_module).tag_transcription
return tag_transcription(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function unitalicize_brackets(...)
unitalicize_brackets = require(italics_module).unitalicize_brackets
return unitalicize_brackets(...)
end
local function upper(...)
upper = require(string_utilities_module).upper
return upper(...)
end
local function usub(...)
usub = require(string_utilities_module).sub
return usub(...)
end
local function yesno(...)
yesno = require(yesno_module)
return yesno(...)
end
local function track(page)
debug_track("quote/" .. page)
end
local function maintenance_line(text)
return '<span class="maintenance-line">(' .. text .. ")</span>"
end
local function isbn(text)
return "[[특수:책찾기/"
.. text
.. "|→ISBN]]"
.. check_isbn(
text,
' <span class="error" style="font-size:88%">잘못된 ISBN</span>[[분류:ISBN 오류가 있는 문서]]'
)
end
local function issn(text)
return "[https://www.worldcat.org/issn/"
.. text
.. " →ISSN]"
.. check_issn(
text,
' <span class="error" style="font-size:88%">잘못된 ISSN</span>[[분류:ISSN 오류가 있는 문서]]'
)
end
local function lccn(text)
text = text:gsub(" ", "")
if text:find("-") then
local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$")
if prefix then
if ulen(part2) < 6 then
part2 = ("0"):rep(6 - ulen(part2)) .. part2
end
text = prefix .. part1 .. part2
end
end
return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]"
end
local function format_date(text)
return mw.getCurrentFrame():callParserFunction("#formatdate", text)
end
-- 날짜 파싱을 위해 위키미디어의 파서 함수를 사용
local function parse_to_ymd(datestr, param)
if not datestr then return nil end
local has_month = datestr:find('월') or datestr:find('%a') or datestr:match('^%d%d%d%d%-%d+')
local has_day = datestr:find('일') or datestr:match('^%d%d%d%d%-%d+%-%d+') or (datestr:match('%a') and datestr:match('%d'))
local parsable_date = datestr:gsub('년', '-'):gsub('월', '-'):gsub('일', ''):gsub('%s', '')
local lang = mw.getContentLanguage()
local ok_y, y = pcall(lang.formatDate, lang, 'Y', parsable_date)
local m, d
if ok_y then
if has_month then
local ok_m, m_val = pcall(lang.formatDate, lang, 'm', parsable_date)
if ok_m then m = m_val end
end
if has_day then
local ok_d, d_val = pcall(lang.formatDate, lang, 'd', parsable_date)
if ok_d then d = d_val end
end
return {y = y, m = m, d = d, original = datestr}
else
return {original = datestr}
end
end
-- YMD 테이블을 "YYYY년 M월 D일" 형식의 문자열로 변환
local function format_kor_date(ymd_table, show_day)
if not ymd_table then return nil end
if not ymd_table.y then return ymd_table.original end
if not ymd_table.m and not ymd_table.d then
return ymd_table.y
end
local date_parts = {ymd_table.y .. "년"}
if ymd_table.m then
table.insert(date_parts, " " .. tonumber(ymd_table.m) .. "월")
if show_day ~= false and ymd_table.d then
table.insert(date_parts, " " .. tonumber(ymd_table.d) .. "일")
end
end
return table.concat(date_parts)
end
-- raw_lb= 매개변수 (또는 nil)를 개별 레이블 정보 객체로 분석한 다음,
-- 각 레이블 명세에 있는 `omit_preComma`, `omit_postSpace` 같은 플래그를 존중하여
-- 한정어(qualifier) 입력값으로 적절하게 연결합니다.
local function parse_and_format_labels(raw_lb, lang)
if not raw_lb then
return nil
end
local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true}
labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true}
if labels ~= "" then -- labels가 빈 문자열일 수도 있는 특정 상황을 대비
return {labels}
end
end
-- 쉼표로 구분된 언어 코드 목록을 쉼표로 구분된 언어 이름 목록으로 변환합니다.
-- `langs`는 언어 코드 목록을 가져온 매개변수의 이름입니다.
local function format_langs(langs)
local names = {}
for i, lang in ipairs(langs) do
names[i] = lang:getCanonicalName()
end
if #names == 1 then
return names[1]
end
return serial_comma_join(names)
end
local function get_first_lang(langs)
return langs[1] or get_lang("und")
end
--[=[
일반적으로 다양한 곳에서 인라인 수식어(inline modifier)와 언어 코드 접두사를 분석합니다.
(예: he:מרים<tr:Miryem>). 하지만 {{l|...}}, {{lang|...}} 등으로 인수를 감싸서 생긴
<span ...>, <i ...>, <br/> 같은 HTML 항목은 제외합니다. 기본적으로 여기서 분석하는 모든 태그는
보다 작음(<) 기호, 글자, 콜론으로 구성되어야 합니다(예: <tr:...>).
따라서 최상위 레벨에서 이런 형식이 아닌 태그가 보이면 분석을 시도하지 않습니다.
최상위 레벨로 제한하는 이유는 한정어 수식어 내부에 생성된 HTML을 허용하기 위함입니다.
(예: foo<q:similar to {{m|fr|bar}}>)
또한 URL처럼 보이는 것들이 언어 코드 접두사로 분석되지 않도록 제외합니다.
]=]
local function val_should_not_be_parsed_for_annotations(val)
return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://")
end
local param_mods = {
t = {
-- <t:...>와 <gloss:...>는 동의어입니다.
item_dest = "gloss",
},
gloss = {},
alt = {},
tr = {},
ts = {},
subst = {},
sc = {type = "script"},
f = {
convert = function(arg, parse_err)
local prefix, val = arg:match("^(.-):([^ ].*)$")
if not prefix then
prefix = ""
val = arg
end
local tags, sc_code, sc = prefix:match("^(.*)/(.-)$")
if sc_code then
sc = get_script(sc_code) or
require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang")
else
tags = prefix
end
local quals
if tags ~= "" then
quals = split_on_comma(tags)
for i, qual in ipairs(quals) do
local obj = get_lang(qual, nil, "allow etym") or get_script(qual)
quals[i] = obj or qual
end
end
return {
quals = quals,
sc = sc,
val = val,
}
end,
store = "insert",
},
q = {},
qq = {},
}
local function generate_obj_annotated_text(text, parse_err, paramname)
local obj = {}
if text:find(":[^ ]") or text:find("%[%[") then
obj.text, obj.lang, obj.link =
parse_term_with_lang{
term = text,
parse_err = parse_err,
paramname = paramname
}
else
obj.text = text
obj.link = text
end
return obj
end
--[=[
외국어 또는 다른 문자로 되어 있을 수 있고, 언어 접두사 및/또는 인라인 수식어로 주석이 달릴 수 있는
텍스트 속성을 분석합니다. `val`은 매개변수의 값이고, `fullname`은 값을 가져온 매개변수의 이름입니다.
`explicit_gloss`가 지정되면 <t:...> 또는 <gloss:...> 인라인 수식어로 지정된 설명을 덮어씁니다.
`val`이 nil이면 이 함수의 반환값은 nil입니다. 그렇지 않으면 언어 접두사(예: 'ar:مُؤَلِّف')와
인라인 수식어(예: 'ar:مُؤَلِّف<t:Author>')를 분석하며, 반환값은 다음 필드를 포함하는 객체입니다:
`lang`: 언어 접두사에 해당하는 언어 객체. 없으면 nil.
`text`: 언어 접두사와 인라인 수식어를 제거한 후의 텍스트.
`link`: 텍스트가 두 부분으로 된 링크인 경우 링크 부분. 아니면 `text`와 동일.
`alt`: <alt:...> 수식어로 지정된 표시 텍스트. 없으면 nil.
`subst`: 음역 생성을 위해 사용된 치환. subst= 매개변수와 동일한 형식.
`sc`: <sc:...> 수식어에 해당하는 문자 객체. 없으면 nil.
`tr`: <tr:...> 수식어에 해당하는 음역. 없으면 nil.
`ts`: <ts:...> 수식어에 해당하는 전사. 없으면 nil.
`gloss`: `explicit_gloss` 매개변수로 지정된 설명. 없으면 <t:...> 또는 <gloss:...> 수식어. 둘 다 없으면 nil.
`f`: 텍스트의 외국어 버전.
`q`: 왼쪽 한정어.
`qq`: 오른쪽 한정어.
특별한 경우로, `val`이 최상위 레벨에 HTML 태그를 포함하면 (예: '<span class="Arab">...</span>'),
언어 접두사나 인라인 수식어를 분석하지 않으며, 반환값은 `noscript` 필드가 true로 설정됩니다.
이는 format_annotated_text() 함수에게 텍스트의 문자를 식별하고 CSS 태그를 지정하지 말고,
태그 없이 그대로 두라고 지시합니다.
이 객체는 format_annotated_text() 함수에 전달되어 텍스트와 수식어를 표시하는 문자열로 형식화될 수 있습니다.
]=]
local function parse_annotated_text(val, fullname, explicit_gloss)
if not val then
return nil
end
-- 인라인 수식어를 확인할 때, {{l|...}}, {{lang|...}} 등으로 인수를 감싸서 생긴
-- <span ...>, <i ...>, <br/> 같은 HTML 항목은 제외합니다.
-- 또한 URL이 언어 코드 접두사로 분석되는 것을 방지합니다.
-- val_should_not_be_parsed_for_annotations()를 참조하세요. 최상위 레벨 HTML이 있는 매개변수 값을 찾으면
-- 'noscript = true'를 추가하여 문자 추론 및 태깅을 시도하지 않도록 합니다.
if val_should_not_be_parsed_for_annotations(val) then
return {text = val, link = val, noscript = true, gloss = explicit_gloss}
end
local obj
if val:find("<") then
-- 인라인 수식어 확인.
obj = parse_inline_modifiers(val, {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_annotated_text,
})
else
obj = generate_obj_annotated_text(val, nil, fullname)
end
if explicit_gloss then
obj.gloss = explicit_gloss
end
return obj
end
local html_entity_char_to_replacement = {
["<"] = TEMP_LT,
[">"] = TEMP_GT,
["["] = TEMP_LBRAC,
["]"] = TEMP_RBRAC,
}
local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code)
-- 엔티티 디코딩을 시도합니다. 성공하면, 특정 특수 HTML 엔티티(괄호류)를 단일 유니코드 문자로 바꿉니다.
-- 그렇지 않으면, 세미콜론이 구분자로 해석되지 않도록 특수 문자로 바꿉니다.
local ch = decode_entities(entity)
if ch ~= entity then
return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON
end
-- 엔티티가 디코딩되지 않으면, 유효한 형식일 경우에만 이스케이프합니다.
if hash == "" then
-- 비표준 미디어위키 전용 엔티티는 이제 걸러졌으므로, ASCII 문자가 아닌 문자는 유효하지 않은 것으로 처리합니다.
return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
elseif x == "" then
return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity
end
local html_entity_replacement_to_char = {
[TEMP_LT] = "<",
[TEMP_GT] = ">",
[TEMP_LBRAC] = "[",
[TEMP_RBRAC] = "]",
[TEMP_SEMICOLON] = ";",
}
local function undo_html_entity_replacement(txt)
-- html_entity_replacement_to_char에 있는 모든 것을 커버하는 패턴.
return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char))
end
-- 참고: 일반적인 경우에 대해 이 함수를 최적화하여 Module:parse utilities를 로드하지 않도록 노력합니다.
-- 해당 모듈 없이 처리할 수 있는 경우는 인라인 수식어나 언어 접두사가 없는 단일 값,
-- 그리고 괄호, 앰퍼샌드, 콜론이 없는 다중 값입니다.
local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement)
local obj = {}
if text:find(":[^ ]") or text:find("%[%[") then
obj.text, obj.lang, obj.link =
parse_term_with_lang{
term = text,
parse_err = parse_err,
paramname = paramname,
}
else
obj.text = text
obj.link = text
end
if not no_undo_html_entity_replacement then
obj.text = undo_html_entity_replacement(obj.text)
obj.link = undo_html_entity_replacement(obj.link)
end
return obj
end
--[=[
parse_annotated_text()와 유사하지만, 매개변수 값이 세미콜론으로 구분된 여러 개체를 포함할 수 있으며,
각각 고유한 인라인 수식어를 가질 수 있습니다.
대괄호, 중괄호, 소괄호 안에 있는 세미콜론은 구분자로 처리되지 않아야 합니다.
또한 세미콜론을 포함하는 HTML 엔티티도 있을 수 있습니다.
반환값은 parse_annotated_text()가 반환하는 것과 같은 종류의 객체 목록입니다.
]=]
local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname)
if not val then
return nil
end
-- 아래 코드에서 'entity'는 주로 세미콜론으로 구분된 값(주로 사람 이름)을 의미합니다.
local splitchar, korean_delim
if val:find("^,") then
splitchar = ","
korean_delim = "쉼표"
val = val:gsub("^,", "")
else
splitchar = ";"
korean_delim = "세미콜론"
end
-- 최적화 #1: 세미콜론/쉼표나 꺾쇠괄호(인라인 수식어)가 없는 경우.
if not val:find("[<" .. splitchar .. "]") then
if val_should_not_be_parsed_for_annotations(val) then
return {{text = val, link = val, noscript = true}}
else
return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")}
end
end
-- 최적화 #2: 세미콜론/쉼표는 있지만, 꺾쇠괄호, 중괄호, 대괄호, 소괄호나 앰퍼샌드가 없는 경우.
if not val:find("[<>%[%](){}&]") then
local entity_objs = {}
for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do
if val_should_not_be_parsed_for_annotations(entity) then
insert(entity_objs, {
text = entity,
link = entity,
noscript = true
})
else
insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement"))
end
end
return entity_objs
end
-- HTML 엔티티를 이스케이프하고 방향성 마커를 제거합니다.
local amp = val:find("&", nil, true)
if amp then
-- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities
-- that have non-ASCII characters in their codes.
val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement)
end
-- left-to-right (U+200E) and right-to-left (U+200F) 마커 제거.
val = val:gsub("\226\128[\142\143]", "")
-- 짝이 맞는 구분자(balanced delimiter)를 분석합니다.
local entity_runs = parse_multi_delimiter_balanced_segment_run(
val,
{{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}},
true
)
if type(entity_runs) == "string" then
local undo_val = undo_html_entity_replacement(val)
-- 짝이 맞지 않는 구분자로 인한 파싱 오류. 오류를 발생시키지 않고 값을 그대로 반환합니다.
return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}}
end
-- 세미콜론(또는 쉼표)으로 분리합니다.
local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*")
-- 각 값을 처리합니다.
local entity_objs = {}
for _, entity_group in ipairs(separated_groups) do
-- <...>가 아닌 부분을 다시 합칩니다.
local j = 2
while j <= #entity_group do
if not entity_group[j]:find("^<.*>$") then
entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1]
remove(entity_group, j)
remove(entity_group, j)
else
j = j + 2
end
end
local oneval = undo_html_entity_replacement(concat(entity_group))
-- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it,
-- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed
-- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more.
if val_should_not_be_parsed_for_annotations(oneval) then
insert(entity_objs, {
text = oneval,
link = oneval,
noscript = true
})
else
local obj
if #entity_group > 1 then
-- 인라인 수식어 확인.
obj = parse_inline_modifiers_from_segments({
group = entity_group,
arg = oneval,
props = {
paramname = fullname,
param_mods = param_mods,
generate_obj = generate_obj_multivalued_annotated_text,
},
})
else
obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname)
end
insert(entity_objs, obj)
end
end
if explicit_gloss then
if #entity_objs > 1 then
error(
(
"|%s=와 |%s=의 여러 %s 구분 개체를 함께 지정할 수 없습니다; "
.. "개별 개체에 <t:...> 인라인 수식어를 사용하세요."
):format(explicit_gloss_fullname, english_delim, fullname)
)
end
entity_objs[1].gloss = explicit_gloss
end
return entity_objs
end
--[=[
외국어 또는 다른 문자로 된 텍스트 속성을 주석과 함께 형식화합니다.
Module:links의 full_link() 함수와 개념적으로 유사하지만, 서지 정보에 더 적합한 다른 형식으로 주석을 표시합니다.
출력 형식은 다음과 같습니다:
TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS]
`textobj`는 parse_annotated_text()가 반환한 객체입니다.
`tag_text_func`는 텍스트 처리 및 CSS 태깅 후 텍스트를 추가로 감싸는 함수입니다.
`tag_gloss_func`는 설명(gloss)에 대한 유사한 함수입니다.
]=]
local function format_annotated_text(textobj, tag_text_func, tag_gloss_func)
if not textobj then
return nil
end
local text, link = textobj.text, textobj.link
local subst, tr, ts, f, gloss, alt = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss, textobj.alt
if alt then
if link:find("%[%[") or link:find("%]%]") then
local errmsg = ("현재 '%s'에 포함된 링크와 <alt:...> 텍스트 '%s'를 함께 처리할 수 없습니다."):format(link, alt)
error(escape_wikicode(errmsg))
end
text = ("[[%s|%s]]"):format(link, alt)
end
-- `noscript`는 텍스트 값에서 HTML이 발견되었음을 의미하며, 아마도 {{lang|...}}을 사용하여 생성된 것입니다.
-- {{lang}}은 이미 텍스트에 문자 태그를 지정하고 내장 언어 링크를 처리하므로 다시 수행하지 않습니다.
if not textobj.noscript then
local lang = textobj.lang
-- 최적화를 위해 ASCII로만 구성된 인수에 대해서는 문자 감지를 수행하지 않습니다.
local sc = textobj.sc
or lang and lang:findBestScript(text)
or not text:find("^[ -~]$") and find_best_script_without_lang(text)
or nil
-- 최적화를 위해 언어, 문자, 음역 또는 전사가 없는 경우 다음을 수행하지 않습니다.
if lang or sc or tr or ts then
if not lang then
lang = get_lang("und")
end
local auto_tr_exclusions = { ["ko"] = true, ["jje"] = true }
if tr == "-" then
tr = nil
elseif not tr and sc and not sc:getCode():find("Lat") and not auto_tr_exclusions[lang:getCode()] then
-- might return nil
local text_for_tr = text
if subst then
text_for_tr = apply_subst(text_for_tr, subst)
else
text_for_tr = remove_links(text)
end
tr = (lang:transliterate(text_for_tr, sc))
end
if text:find("%[%[") then
text = embedded_language_links({
term = text,
lang = lang,
sc = sc,
})
end
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
text = tag_text(text, lang, sc)
end
if tr then
tr = tag_translit(tr, lang, "usex")
end
if ts then
ts = tag_transcription(ts, lang, "usex")
end
end
end
text = unitalicize_brackets(text)
if tag_text_func then
text = tag_text_func(text)
end
local parts = {}
if textobj.q then
insert(parts, format_qualifier(textobj.q) .. " ")
end
insert(parts, text)
if tr or ts or f or gloss then
insert(parts, " (") -- 여는 괄호
local subparts = {}
if tr then
insert(subparts, "음역: " .. tr)
end
if ts then
insert(subparts, "발음: /" .. ts .. "/")
end
if f then
for _, ff in ipairs(f) do
local sc = ff.sc
local lang
if not sc and ff.quals then
local qual = ff.quals[1]
if type(qual) == "string" then
-- 아무것도 하지 않음. 아래에서 문자 감지를 수행함.
elseif qual:hasType("script") then
sc = qual
else -- language
sc = qual:findBestScript(ff.val)
lang = qual
end
end
if not lang then
lang = get_lang("und")
end
sc = sc or find_best_script_without_lang(ff.val)
local val = embedded_language_links({
term = ff.val,
lang = lang,
sc = sc,
})
if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then
val = tag_text(val, lang, sc)
end
local qual_prefix
if ff.quals then
for i, qual in ipairs(ff.quals) do
if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then
ff.quals[i] = qual:getCanonicalName()
end
end
qual_prefix = concat(ff.quals, "/") .. ": "
else
qual_prefix = ""
end
insert(subparts, qual_prefix .. val)
end
end
if gloss then
gloss = '<span class="e-translation">' .. gloss .. "</span>"
gloss = unitalicize_brackets(gloss)
if tag_gloss_func then
gloss = tag_gloss_func(gloss)
end
insert(subparts, "번역: " .. gloss)
end
insert(parts, concat(subparts, ", "))
insert(parts, ")") -- 닫는 괄호
end
if textobj.qq then
insert(parts, " " .. format_qualifier(textobj.qq))
end
return concat(parts)
end
--[=[
외국어 또는 다른 문자로 된 다중 값 텍스트 속성을 주석과 함께 형식화합니다.
이것은 format_annotated_text()의 다중 값 버전이며, 각 개별 개체를
format_annotated_text()를 사용하여 형식화하고 결과를 `delimiter`로 결합합니다.
기본값은 ", "입니다. `delimiter`가 "and" 또는 "or"이면 지정된 접속사로 결합합니다.
`textobjs`는 parse_multivalued_annotated_text()가 반환한 객체입니다.
`tag_text_func`와 `tag_gloss_func`는 format_annotated_text()에서와 동일합니다.
]=]
local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func)
if not textobjs then
return nil
end
if #textobjs == 1 then
return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func)
end
local parts = {}
for _, textobj in ipairs(textobjs) do
insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func))
end
local n = #parts
-- 한국어화 주석: 'et al.'을 '외'로 처리합니다.
if n > 0 and parts[n]:match("^'*외[%.']*$") then
parts[n] = "''외''"
if n == 2 then
return concat(parts, " ")
end
if delimiter == "and" or delimiter == "or" then
delimiter = ", "
end
return concat(parts, delimiter)
end
if delimiter == "and" or delimiter == "or" then
return serial_comma_join(parts, {conj = delimiter})
end
return concat(parts, delimiter or ", ")
end
-- ine() (if-not-empty)의 향상된 버전. 빈 문자열을 nil로 변환하고, 앞뒤 공백도 제거합니다.
local function ine(arg)
if not arg then
return nil
elseif type(arg) ~= "string" then
return arg
end
arg = mw.text.trim(arg)
if arg == "" then
return nil
end
return arg
end
local abbrs = {
["a."] = {anchor = "a.", full = "이전(ante)"},
["c."] = {anchor = "c.", full = "대략(circa)"},
["p."] = {anchor = "p.", full = "이후(post)"},
}
-- 임의의 날짜 또는 연도 사양 시작 부분의 접두사 'a.' (ante), 'c.' (circa), 'p.' (post)를 처리합니다.
-- 두 개의 값을 반환합니다: 형식화된 접두사와 접두사가 제거된 날짜 사양.
-- 접두사가 없으면 빈 문자열과 전체 날짜를 반환합니다.
local function process_ante_circa_post(date)
local prefix = usub(date, 1, 2)
local abbr = abbrs[prefix]
local abbr_prefix = ""
if abbr then
abbr_prefix = "''[[부록:용어집#"
.. abbr.anchor
.. '|<abbr title="'
.. abbr.full
.. '">'
.. abbr.anchor
.. "</abbr>]]'' "
-- 날짜 매개변수 시작 부분의 소문자, 마침표, 공백을 제거합니다.
date = ugsub(date, "^%l%.%s*", "")
end
return abbr_prefix, date
end
-- 인용 날짜를 지정하는 인수들의 형식을 지정합니다.
local function format_date_args(
a,
get_full_paramname,
alias_map,
parampref,
paramsuf,
bold_year, -- 호환성을 위해 유지
maintenance_line_no_date,
year_last -- 호환성을 위해 유지
)
local output = {}
parampref = parampref or ""
paramsuf = paramsuf or ""
local function getp(param)
return a(parampref .. param .. paramsuf)
end
local function pname(param)
local fullname = get_full_paramname(parampref .. param .. paramsuf)
return alias_map[fullname] or fullname
end
local start_date_str = getp("start_date")
local date_str = getp("date")
local year = getp("year")
local month = getp("month")
local start_year = getp("start_year")
local start_month = getp("start_month")
if not start_date_str and start_year then
local start_year_val = (tostring(start_year):gsub('년', ''))
if start_month then
local start_month_val = (tostring(start_month):gsub('월', ''))
start_date_str = start_year_val .. "년 " .. start_month_val .. "월"
else
start_date_str = start_year_val .. "년"
end
end
-- 오류 검사
if date and year then
error(
("|%s= 또는 |%s= 중 하나만 지정해야 합니다."):format(
pname("date"),
pname("year")
)
)
end
if start_date_str and start_year then
error(
("|%s=|와 |%s=| 중 하나만 지정해야 합니다."):format(
pname("start_date"),
pname("start_year")
)
)
end
if (start_date_str or start_year) and not (date_str or year) then
error(
("|%s=| 또는 |%s=/%s=|가 없으면 |%s=| 또는 |%s=/%s=|를 지정할 수 없습니다."):format(
pname("date"),
pname("year"),
pname("month"),
pname("start_date"),
pname("start_year"),
pname("start_month")
)
)
end
-- 최종 날짜 및 시작 날짜 조합
local final_date_str = date_str or (year and (month and year .. " " .. month or year))
local final_start_date_str = start_date_str or (start_year and (start_month and start_year .. " " .. start_month or start_year))
local final_date_parts = parse_to_ymd(final_date_str)
local final_start_date_parts = parse_to_ymd(final_start_date_str)
local date_has_day = date_str and (date_str:find("일") or tonumber(final_date_parts.d) ~= 1)
local start_date_has_day = start_date_str and (start_date_str:find("일") or tonumber(final_start_date_parts.d) ~= 1)
-- circa 등 접두사 처리
if final_start_date_parts then
local abbr_prefix, original = process_ante_circa_post(final_start_date_parts.original)
final_start_date_parts.original = original
insert(output, abbr_prefix)
elseif final_date_parts then
local abbr_prefix, original = process_ante_circa_post(final_date_parts.original)
final_date_parts.original = original
insert(output, abbr_prefix)
end
if final_start_date_parts then -- 날짜 범위가 있는 경우
insert(output, format_kor_date(final_start_date_parts, start_date_has_day))
if final_date_parts.y and final_date_parts.y ~= final_start_date_parts.y then
-- 연도가 다르면 전체 종료 날짜를 표시
insert(output, " – ")
insert(output, format_kor_date(final_date_parts, date_has_day))
elseif final_date_parts.m and final_date_parts.m ~= final_start_date_parts.m then
-- 연도는 같고 월이 다르면, 월과 일을 표시
insert(output, " – ")
local end_date_parts = {}
insert(end_date_parts, tonumber(final_date_parts.m) .. "월")
if date_has_day then
insert(end_date_parts, " " .. tonumber(final_date_parts.d) .. "일")
end
insert(output, table.concat(end_date_parts))
elseif final_date_parts.d and final_date_parts.d ~= final_start_date_parts.d then
-- 연도와 월이 같고 일이 다르면, 일만 표시
insert(output, "–")
insert(output, tonumber(final_date_parts.d) .. "일")
end
elseif final_date_parts then -- 단일 날짜
insert(output, format_kor_date(final_date_parts, date_has_day))
elseif not maintenance_line_no_date then
-- 주 인용 날짜가 아님. nil을 반환하면 호출자가 처리함.
return nil, nil
elseif not getp("nodate") then
local accessdate = getp("accessdate")
if accessdate then
insert(output, format_kor_date(parse_to_ymd(accessdate), true) .. " (마지막 확인)")
else
if mw.title.getCurrentTitle().namespace ~= 10 then -- 틀 이름공간이 아니면
return maintenance_line(maintenance_line_no_date), true
end
return nil, nil
end
end
return ine(concat(output)), nil
end
local function tag_with_cite(txt)
-- <cite> 태그 대신 겹낫표 『』를 사용합니다.
-- 책 제목, 저널 이름 등에 적용됩니다.
return "『" .. txt .. "』"
end
-- 인용의 출처 라인을 표시합니다. 이 부분에 모듈 로직의 대부분이 포함되어 있습니다.
function export.source(args, alias_map, format_as_cite, other_controls)
local tracking_categories = {}
local argslang = args[1] or args.lang
if not argslang then
local current_title = mw.title.getCurrentTitle()
if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then
require(languages_error_module)(nil, 1)
end
end
local function alias(param)
return alias_map[param] or param
end
local output, sep = {}
local overrides = other_controls and other_controls.overrides or {}
local function add(text)
if sep then
insert(output, sep)
end
insert(output, text)
sep = nil
end
local function add_with_sep(text, next_sep)
add(text)
sep = next_sep or ". "
end
local function make_get_full_paramname(ind)
return function(param)
return param .. ind
end
end
local get_full_paramname
local function a_with_name(param)
if not param then
return nil
elseif type(param) ~= "table" then
local fullname = get_full_paramname(param)
return args[fullname], alias(fullname)
end
for _, par in ipairs(param) do
local val, fullname = a_with_name(par)
if val then
return val, alias(fullname)
end
end
return nil
end
local function a(param)
return (a_with_name(param))
end
local function aurl_with_name(param)
local value, fullname = a_with_name(param)
if value and value:find(" ") and not value:find("%[") then
error(("URL에 공백을 포함할 수 없습니다: |%s=%s"):format(fullname, value))
end
return value, fullname
end
local function aurl(param)
return (aurl_with_name(param))
end
local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local obj = parse_annotated_text(val, fullname)
return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname
end
local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func)
return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func))
end
local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)
local val, fullname = a_with_name(param)
local objs = parse_multivalued_annotated_text(val, fullname)
local num_objs = objs and #objs or 0
return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs
end
local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func)
return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func))
end
local author_outputted = false
local date_outputted, formatted_date, formatted_origdate = false
local function add_date(no_paren)
if not date_outputted then
if formatted_date or formatted_origdate then
if formatted_date then
add(" (" .. formatted_date .. ")")
end
if formatted_origdate then
add(SPACE_LBRAC .. formatted_origdate .. RBRAC)
end
sep = ". "
end
date_outputted = true
end
end
local function is_anonymous(val)
return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") or val == "작자 미상"
end
local function has_newversion()
return a("2ndauthor") or a("2ndlast") or a("chapter2") or a("title2") or
a("tlr2") or a("mainauthor2") or a("editor2") or a("editors2") or
a("newversion") or a("location2") or a("publisher2") or a("year2") or
a("date2") or a("page2")
end
local function add_newversion()
sep = nil
add(SEMICOLON_SPACE)
add(a("newversion") or "재출간:")
add(" ")
end
local function add_author(
author, author_fullname, trans_author, trans_author_fullname,
authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname,
first, first_fullname, trans_first, trans_first_fullname,
last, last_fullname, trans_last, trans_last_fullname,
last_first
)
local function make_author_with_url(txt, txtparam, authorlink, authorlink_param)
if authorlink then
if authorlink:find("%[%[") then
error(("|%s=%s에 링크를 지정할 수 없습니다."):format(authorlink_param, authorlink))
end
if txt:find("%[%[") then
error(("%s=%s에 링크를 지정할 수 없습니다."):format(txtparam, txt))
end
return "[[w:" .. authorlink .. "|" .. txt .. "]]"
else
return txt
end
end
local num_authorobjs
if author then
local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname)
num_authorobjs = #authorobjs
if num_authorobjs == 1 then
if is_anonymous(authorobjs[1].text) then
authorobjs[1].text = "작자 미상"
authorobjs[1].link = "작자 미상"
end
if authorlink then
authorobjs[1].text = make_author_with_url(authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname)
authorobjs[1].link = make_author_with_url(authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname)
end
if authorobjs[1].gloss and trans_authorlink then
authorobjs[1].gloss = make_author_with_url(authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname)
end
add(format_multivalued_annotated_text(authorobjs, "; "))
else
local formatted_text = format_multivalued_annotated_text(authorobjs, "; ")
if authorlink then
formatted_text = make_author_with_url(formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname)
end
add(formatted_text)
end
else
num_authorobjs = 1
if first then
if last_first then
author = last .. ", " .. first
else
author = first .. " " .. last
end
else
author = last
end
if authorlink then
local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname
author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname)
end
local trans_author
if trans_last then
if trans_first then
trans_author = trans_first .. " " .. trans_last
else
trans_author = trans_last
end
if trans_authorlink then
local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname
trans_author = make_author_with_url(trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname)
end
end
add(author)
if trans_author then
add(" (" .. trans_author .. ")")
end
end
author_outputted = true
return num_authorobjs
end
local function add_authorlike(param, prefix_when_author, suffix_no_author, suffix_multiple)
local delimiter = "; "
local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter)
if not entities then return end
local suffix = suffix_no_author
if num_entities > 1 and suffix_multiple then
suffix = suffix_multiple
end
if is_anonymous(entities) then
add_with_sep("작자 미상의" .. suffix)
else
if author_outputted then
add_with_sep(prefix_when_author .. entities)
else
add_with_sep(entities .. " (" .. suffix .. ")")
end
end
author_outputted = true
end
local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix)
local chap, chap_fullname = a_with_name(param)
if not chap then return nil end
-- 저널 인용 등에서 chapterurl 대신 url을 사용하도록 수정
local chapterurl = aurl(param .. "url") or aurl("url")
local function make_chapter_with_url(chap_text)
return chapterurl and ("[" .. chapterurl .. " " .. chap_text .. "]") or chap_text
end
local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param))
chapterobj.text = make_chapter_with_url(chapterobj.text)
chapterobj.link = make_chapter_with_url(chapterobj.link)
return "「" .. format_annotated_text(chapterobj) .. "」"
end
-- 저자 정보 출력 후 나머지 모든 서지 정보를 처리하는 함수
local function postauthor(ind, num_authors, format_as_cite)
get_full_paramname = make_get_full_paramname(ind)
-- URL이 챕터(기사 제목)에 이미 사용되었는지 추적하는 변수
local url_already_used = (a("chapter") or a("episode")) and (a("chapterurl") or a("url"))
-- 1. 챕터/항목 (제목 등)
local formatted_entry = format_chapterlike("entry") or format_chapterlike("chapter") or format_chapterlike("episode")
if formatted_entry then
add_with_sep(formatted_entry)
end
-- 2. 제목 (책, 저널 등)
local title_param_name = "title"
if (args.type == "journal" or args.magazine) and not args.title then
title_param_name = "magazine"
end
local title, title_fullname = a_with_name(title_param_name)
if title then
-- URL이 챕터에 사용되지 않았을 경우, 주 제목에 URL을 링크합니다.
local title_url = not url_used_for_chapter and aurl("url")
local function tag_title_with_link(txt)
local linked_txt = title_url and ("[" .. title_url .. " " .. txt .. "]") or txt
return "『" .. linked_txt .. "』"
end
local titleobj = parse_annotated_text(title, title_fullname, a("trans-" .. title_param_name))
add(format_annotated_text(titleobj, tag_title_with_link))
elseif ind == "" and not a("notitle") then
add(maintenance_line("책 제목이나 저널명을 입력해주세요."))
end
-- 3. 시리즈 정보
local series = parse_and_format_annotated_text("series")
if series then
add(" (" .. series)
local seriesvolume = parse_and_format_annotated_text("seriesvolume")
if seriesvolume then
add(SEMICOLON_SPACE .. seriesvolume)
end
add(")")
end
sep = ". "
local season = a("season")
if season then
add_with_sep("시즌 " .. season)
end
local number = a("number")
if number then
add_with_sep(number .. "화")
end
local note = a("note")
if note then
add(note)
end
-- 4. 편집자, 번역가 등
add_authorlike("editor", nil, "엮음", "엮음")
add_authorlike("tlr", nil, "번역", "번역")
-- 5. 판차
local edition = parse_and_format_annotated_text("edition")
if edition then add_with_sep(edition .. "판") end
-- 6. 출판 정보 (장소, 출판사)
local location = parse_and_format_multivalued_annotated_text("location")
local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ")
if publisher then
if location then
add_with_sep(location .. ": " .. publisher)
else
add_with_sep(publisher)
end
elseif location then
add_with_sep(location)
end
-- 7. 페이지 (URL 링크 기능 추가)
local page = a("page") or a("pages")
if page then
local pageurl = aurl("pageurl")
if pageurl then
add_with_sep("[" .. pageurl .. " " .. page .. "쪽]")
else
add_with_sep(page .. "쪽")
end
end
-- 8. 식별자 (DOI, ISBN 등)
local function small(txt)
add("<small>" .. txt .. "</small>")
end
local function add_identifier(param_or_params, pretext, posttext, process)
local val = a(param_or_params)
if val then
val = (process or mw.uri.encode)(val)
small(pretext .. val .. posttext)
end
end
add_identifier("issn", "[https://www.worldcat.org/issn/", " →ISSN]")
add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]")
add_identifier("isbn", "", "", isbn)
add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>")
local id = a("id")
if id then small(id) end
-- 9. 확인 날짜 및 보존 정보
local archiveurl = aurl("archiveurl")
local accessdate = a("accessdate")
local original_url = aurl("url")
if archiveurl or accessdate then
local text_to_add = ""
if archiveurl then
local original_url = aurl("url")
local archivedate_str = a("archivedate")
local formatted_archivedate = ""
if archivedate_str then
formatted_archivedate = format_kor_date(parse_to_ymd(archivedate_str), true)
end
local archive_text = ""
if original_url then
archive_text = "[" .. original_url .. " 원본 문서]에서 "
end
archive_text = archive_text .. "[" .. archiveurl .. " 보존된 사본]"
if formatted_archivedate and formatted_archivedate ~= "" then
archive_text = archive_text .. " (" .. formatted_archivedate .. ")"
end
add_with_sep(archive_text)
-- |date=나 |year=가 있을 때만 "확인함" 정보를 맨 뒤에 추가합니다.
elseif accessdate and (a("date") or a("year")) then
local formatted_accessdate = format_kor_date(parse_to_ymd(accessdate), true)
add_with_sep(formatted_accessdate .. "에 확인함")
end
sep = ". "
add(text_to_add)
end
end
local function add_authors(args, last_first)
local maxind = math.max(args.author.maxindex, args.last.maxindex)
local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"}
for _, ancillary in ipairs(ancillary_params) do
maxind = math.max(maxind, args[ancillary].maxindex)
end
local num_authors = 0
for i = 1, maxind do
local ind = i == 1 and "" or i
local author, last = args.author[i], args.last[i]
if author or last then
local this_num_authors = add_author(
author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind,
args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind,
args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind,
last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind,
last_first
)
num_authors = num_authors + this_num_authors
sep = ""
else
for _, cant_have in ipairs(ancillary_params) do
if args[cant_have][i] then
error(("|%s%s= 없이 |author%s= 또는 |last%s=를 지정할 수 없습니다."):format(cant_have, ind, ind, ind))
end
end
end
end
return num_authors
end
------------------- 여기서부터 텍스트 출력을 시작합니다 ----------------------
get_full_paramname = make_get_full_paramname("")
-- 1. 원본 날짜 정보 처리
formatted_date, need_date = format_date_args(a, get_full_paramname, alias_map, nil, nil, nil, "인용 날짜를 입력해주세요.")
formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, nil)
-- 2. 원본 저자 및 서지 정보 출력
local num_authors = add_authors(args)
add_date()
postauthor("", num_authors, format_as_cite)
-- 3. 재출간/번역 등 'newversion' 처리
if has_newversion() then
add_newversion()
get_full_paramname = make_get_full_paramname("2")
-- |2ndauthor= 또는 |2ndlast=가 있을 때만 저자 정보를 추가합니다.
local num_authors2 = 0
if a("2ndauthor") or a("2ndlast") then
num_authors2 = add_authors(args)
end
local formatted_date2, _ = format_date_args(a, get_full_paramname, alias_map, nil, nil, nil, nil)
if formatted_date2 then
if num_authors2 > 0 then
add(" (" .. formatted_date2 .. ")")
else
add(formatted_date2)
end
sep = ". "
end
postauthor("2", num_authors2, format_as_cite)
end
-- 최종 문자열을 조립합니다.
local output_text = concat(output)
if sep then -- 남아있는 구분자가 있으면 추가합니다.
output_text = output_text .. sep
end
-- 4. 최종 구두점 처리
if not args.nocolon then
-- 문자열 끝의 공백이나 구분자를 모두 제거하고,
output_text = output_text:gsub("%s*[%.%s,;]%s*$", "")
-- 최종 마침표를 하나만 추가합니다.
output_text = output_text .. "."
end
-- 5. 분류 추가 로직
local categories = {}
if not args.nocat then
if need_date then
local argslangobj = get_first_lang(argslang)
insert(categories, "인용 날짜가 필요한 " .. argslangobj:getCanonicalName() .. " 항목")
end
end
return output_text .. ((#categories > 0 and format_categories(categories, get_first_lang(argslang), args.sort) or ""))
end
-- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical
-- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2"
-- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should
-- process this spec if type2= is being handled.
local type_alias_specs = {
book = {
{"author", "3"},
{"title", "4"},
{"url", "5"},
{"year", "2"},
{"page", "6"},
{"text", "7"},
{"t", "8"},
},
journal = {
{"year", "2"},
{"author", "3"},
{"chapter", "title,article,4", true},
{"chapterurl", "titleurl,articleurl", true},
{"trans-chapter", "trans-title,trans-article", true},
{"chapter_tlr", "article_tlr", true},
{"chapter_series", "article_series", true},
{"chapter_seriesvolume", "article_seriesvolume", true},
{"chapter_number", "article_number", true},
{"chapter_plain", "title_plain,article_plain", true},
{"title", "journal,magazine,newspaper,work,5", true},
{"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true},
{"url", "6"},
{"page", "7"},
{"source", "newsagency", true},
{"text", "8"},
{"t", "9"},
},
}
-- `type=` 또는 `type2=`를 사용한 내부 지정 별칭 처리
local function process_type_aliases(args, typ, newversion, alias_map)
local ind = newversion and "2" or ""
local deprecated = ine(args.lang)
if not type_alias_specs[typ] then
local possible_values = {}
for possible, _ in pairs(type_alias_specs) do
insert(possible_values, possible)
end
sort(possible_values)
error(
("type%s=에 인식할 수 없는 값 '%s'이(가) 있습니다; 가능한 값은 %s입니다."):format(
typ,
ind,
concat(possible_values, ",")
)
)
end
for _, alias_spec in ipairs(type_alias_specs[typ]) do
local canon, aliases, with_newversion = unpack(alias_spec)
if with_newversion or not newversion then
canon = canon .. ind
aliases = split(aliases, ",", true)
local saw_alias = nil
for _, alias in ipairs(aliases) do
if alias:match("^%d+$") then
alias = tonumber(alias)
if deprecated then
alias = alias - 1
end
else
alias = alias .. ind
end
if args[alias] then
if saw_alias == nil then
saw_alias = alias
else
error(("|%s=|와 |%s=|는 별칭 관계입니다; 둘 다 값을 지정할 수 없습니다."):format(saw_alias, alias))
end
end
end
if saw_alias and (not newversion or type(saw_alias) == "string") then
if args[canon] then
error(("|%s=|는 |%s=|의 별칭입니다; 둘 다 값을 지정할 수 없습니다."):format(saw_alias, canon))
end
args[canon] = args[saw_alias]
-- Wipe out the original after copying. This is important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_alias] = nil
alias_map[canon] = saw_alias
end
end
end
end
-- 프레임 인수와 부모 인수를 복제하고 결합하며, 빈 문자열은 nil로 처리합니다.
-- 별칭(alias)과 무시(ignore)할 매개변수도 처리합니다.
local function clone_args(direct_args, parent_args)
local args = {}
-- 부모 인수를 먼저 처리하여 직접 인수가 부모 인수를 덮어쓰도록 합니다.
for pname, param in pairs(parent_args) do
track("param/" .. pname)
args[pname] = ine(param)
end
-- 무시할 매개변수 처리. `ignore` 값은 무시할 매개변수 이름의 쉼표 구분 목록입니다.
local ignores = ine(direct_args.ignore)
if ignores then
for ignore in gsplit(ignores, "%s*,%s*") do
args[ignore] = nil
end
end
local alias_map = {}
local other_controls = {}
-- 로마 숫자 자동 변환을 비활성화할 매개변수 처리
local noroman = ine(direct_args.noroman)
if noroman then
other_controls.overrides = other_controls.overrides or {}
for param in gsplit(noroman, "%s*,%s*") do
other_controls.overrides[param] = (other_controls.overrides[param] or {})
other_controls.overrides[param].noroman = true
end
end
-- Process internally-specified aliases using type= or type2=.
local typ = args.type or direct_args.type
if typ then
process_type_aliases(args, typ, false, alias_map)
end
local typ2 = args.type2 or direct_args.type2
if typ2 then
process_type_aliases(args, typ2, true, alias_map)
end
-- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which
-- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an
-- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for
-- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or
-- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias
-- must be specified before the journal/work -> title alias.
--
-- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so
-- that when we would display an error message about DEST, we display SOURCE instead.
--
-- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up
-- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does
-- this).
--
-- FIXME: Delete this once we've converted all alias processing to internal.
local aliases = ine(direct_args.alias)
if aliases then
-- Allow and discard a trailing semicolon, to make managing multiple aliases easier.
aliases = ugsub(aliases, "%s*;$", "")
for alias_spec in gsplit(aliases, "%s*;%s*") do
local alias_spec_parts = split(alias_spec, "%s*:%s*")
if #alias_spec_parts ~= 2 then
error(("별칭 지정 '%s'에는 콜론이 하나만 있어야 합니다."):format(alias_spec))
end
local dest, sources = unpack(alias_spec_parts)
sources = split(sources, "%s*,%s*")
local saw_source = nil
for _, source in ipairs(sources) do
if source:match("^%d+$") then
source = tonumber(source)
end
if args[source] then
if saw_source == nil then
saw_source = source
else
error(("|%s=|와 |%s=|는 별칭 관계입니다; 둘 다 값을 지정할 수 없습니다."):format(saw_source, source))
end
end
end
if saw_source then
if args[dest] then
error(("|%s=|는 |%s=|의 별칭입니다; 둘 다 값을 지정할 수 없습니다."):format(saw_source, dest))
end
args[dest] = args[saw_source]
-- Wipe out the original after copying. This important in case of a param that has general significance
-- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and
-- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled
-- parameter checking.
args[saw_source] = nil
alias_map[dest] = saw_source
end
end
end
-- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen
-- in parent_args (they are params we overwrite in the direct args).
local error_ifs = ine(direct_args.error_if)
if error_ifs then
for error_if in gsplit(error_ifs, "%s*,%s*") do
if ine(parent_args[error_if]) then
error(
("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format(
error_if,
ine(parent_args[error_if])
)
)
end
end
end
for pname, param in pairs(direct_args) do
-- 제어 매개변수 무시
if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then
args[pname] = ine(param)
end
end
return args, alias_map, other_controls
end
local function get_args(frame_args, parent_args, require_lang)
-- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is
-- wasteful of memory.
local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args)
local deprecated = ine(parent_args.lang)
local alias_of_t = {alias_of = "t"}
local boolean = {type = "boolean"}
local language_sublist = {type = "language", sublist = true}
local list_allow_holes = {list = true, allow_holes = true}
local script = {type = "script"}
-- First, the "single" params that don't have FOO2 or FOOn versions.
local params = {
[deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"},
["lang"] = {alias_of = (deprecated and "lang" or 1)},
["언어"] = {alias_of = (deprecated and "lang" or 1)},
["lang2"] = language_sublist,
["newversion"] = true,
["author"] = list_allow_holes,
["저자"] = {alias_of = "author"},
["2ndauthor"] = true,
["trans-author"] = list_allow_holes,
["authorlink"] = list_allow_holes,
["저자링크"] = {alias_of = "authorlink"},
["2ndauthorlink"] = true,
["trans-authorlink"] = list_allow_holes,
["first"] = list_allow_holes,
["이름"] = {alias_of = "first"},
["2ndfirst"] = true,
["trans-first"] = list_allow_holes,
["last"] = list_allow_holes,
["성"] = {alias_of = "last"},
["2ndlast"] = true,
["trans-last"] = list_allow_holes,
["nocat"] = boolean,
["분류없음"] = {alias_of = "nocat"},
["nocolon"] = boolean,
-- 인용문 관련 매개변수
["text"] = true,
["passage"] = {alias_of = "text"},
["인용"] = {alias_of = "text"},
["인용문"] = {alias_of = "text"},
["tr"] = true,
["transliteration"] = {alias_of = "tr"},
["ts"] = true,
["transcription"] = {alias_of = "ts"},
["norm"] = true,
["normalization"] = {alias_of = "norm"},
["sc"] = script,
["normsc"] = script,
["sort"] = true,
["subst"] = true,
["footer"] = true,
["lit"] = true,
["t"] = true,
["translation"] = alias_of_t,
["번역"] = alias_of_t,
["gloss"] = alias_of_t,
["lb"] = true,
["brackets"] = boolean,
-- 원문 인용 관련 매개변수
["origtext"] = true,
["origtr"] = true,
["origts"] = true,
["orignorm"] = true,
["origsc"] = script,
["orignormsc"] = script,
["origsubst"] = true,
["origlb"] = true,
["usenodot"] = boolean,
["nodot"] = boolean,
["inline"] = boolean,
}
-- 대부분의 매개변수는 `PARAM2` 형태를 가집니다.
local function add_with_2(param, value)
params[param] = value
params[param .. "2"] = value
end
local function alias_with_2(alias, canon)
params[alias] = {alias_of = canon}
params[alias .. "2"] = {alias_of = canon .. "2"}
end
for _, param12 in ipairs{
"worklang",
"termlang",
"origlang",
"origworklang"
} do
add_with_2(param12, language_sublist)
end
-- Then the newversion params (which have FOO2 versions).
for _, param12 in ipairs{
-- author-like params; author params themselves are either list params (author=, last=, etc.) or single params
-- (2ndauthor=, 2ndlast=, etc.)
"coauthors",
"quotee",
"tlr",
"editor",
"editors",
"mainauthor",
"compiler",
"compilers",
"director",
"directors",
"lyricist",
"lyrics-translator",
"composer",
"role",
"actor",
"artist",
"feat",
"season",
-- author control params
"default-authorlabel",
"authorlabel",
-- title
"title",
"trans-title",
"series",
"seriesvolume",
"notitle",
-- entry
"entry",
"entryurl",
"trans-entry",
-- chapter
"chapter",
"chapterurl",
"chapter_number",
"chapter_plain",
"chapter_series",
"chapter_seriesvolume",
"trans-chapter",
"chapter_tlr",
-- section
"section",
"sectionurl",
"section_number",
"section_plain",
"section_series",
"section_seriesvolume",
"trans-section",
-- other video-game params
"system",
"scene",
"level",
-- URL
"url",
"urls",
"archiveurl",
-- edition
"edition",
"edition_plain",
-- ID params
"bibcode",
"doi",
"isbn",
"issn",
"jstor",
"lccn",
"oclc",
"ol",
"pmid",
"pmcid",
"ssrn",
"urn",
"id",
-- misc date params; most date params handled below
"archivedate",
"accessdate",
"nodate",
-- numeric params handled below
-- other params
"type",
"genre",
"format",
"medium",
"others",
"quoted_in",
"location",
"publisher",
"original",
"by",
"deriv",
"note",
"note_plain",
"other",
"source",
"platform",
} do
add_with_2(param12, true)
end
-- Then the aliases of newversion params (which have FOO2 versions).
for _, param12_aliased in ipairs{
{"role", "roles"},
{"role", "speaker"},
{"tlr", "translator"},
{"tlr", "translators"},
{"doi", "DOI"},
{"isbn", "ISBN"},
{"issn", "ISSN"},
{"jstor", "JSTOR"},
{"lccn", "LCCN"},
{"oclc", "OCLC"},
{"ol", "OL"},
{"pmid", "PMID"},
{"pmcid", "PMCID"},
{"ssrn", "SSRN"},
{"urn", "URN"},
} do
local canon, alias = unpack(param12_aliased)
alias_with_2(alias, canon)
end
-- Then the date params.
for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do
local pref, suf = unpack(datelike)
for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do
add_with_2(pref .. arg .. suf, true)
end
end
local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"}
-- Then the numeric params.
for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do
for _, suf in ipairs(numeric_param_suffixes) do
add_with_2(numeric .. suf, true)
end
end
-- And the aliases of numeric params.
for _, numeric_aliased in ipairs{{"volume", "vol"}} do
local canon, alias = unpack(numeric_aliased)
for _, suf in ipairs(numeric_param_suffixes) do
alias_with_2(alias .. suf, canon .. suf)
end
end
return process_params(cloned_args, params), alias_map, other_controls
end
local function get_origtext_params(args)
local origtext, origtextlang, origsc, orignormsc
if args.origtext then
-- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or
-- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology
-- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been
-- eliminated.)
origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$")
if not origtextlang then
-- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL.
origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$")
end
if not origtextlang then
error("origtext=는 언어 코드 접두사로 시작해야 합니다.")
end
origtextlang = get_lang(origtextlang, nil, "allow etym") or
error("origtext=는 언어 코드 접두사로 시작해야 합니다.")
origsc = args.origsc
orignormsc = args.orignormsc
else
for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do
if args[noparam] then
error(("%s=는 origtext= 없이 지정할 수 없습니다."):format(noparam))
end
end
end
return origtext, origtextlang, origsc, orignormsc
end
local function get_quote(args, is_cite)
local text = args.text
local gloss = args.t
local tr = args.tr
local ts = args.ts
local norm = args.norm
local sc = args.sc
local normsc = args.normsc
-- Fetch original-text parameters.
local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args)
-- 인용 관련 인수가 있으면 인용문을 표시하고, 그렇지 않으면 아무것도 표시하지 않습니다.
if text or gloss or tr or ts or norm or args.origtext then
-- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages
-- in any case in source() if the language is omitted.
local lang = get_first_lang(args[1] or args.lang)
local termlang = args.termlang and get_first_lang(args.termlang) or lang
local usex_data = {
lang = lang,
termlang = termlang,
usex = text,
sc = sc,
translation = gloss,
normalization = norm,
normsc = normsc,
transliteration = tr,
transcription = ts,
brackets = args.brackets,
subst = args.subst,
lit = args.lit,
footer = args.footer,
qq = parse_and_format_labels(args.lb, lang),
quote = "quote-meta",
orig = origtext,
origlang = origtextlang,
origsc = origsc,
orignorm = args.orignorm,
orignormsc = orignormsc,
origtr = args.origtr,
origts = args.origts,
origsubst = args.origsubst,
origqq = parse_and_format_labels(args.origlb, lang),
noreq = args.noreq,
nocat = is_cite or args.nocat,
}
if args.inline then
-- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text
usex_data.footer = nil
usex_data.inline = 1
text = format_usex(usex_data)
if text then
text = " “" .. text .. "”"
else
text = ""
end
if args.footer then
text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>"
end
else
text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>"
end
elseif args.footer then
text = "<dl><dd>" .. args.footer .. "</dd></dl>"
end
return text
end
-- 틀에서 호출하기 위한 외부 인터페이스 ({{quote-*}} 계열 틀의 기본 인터페이스)
function export.quote_t(frame)
local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang")
local parts = {}
insert(parts, '<div class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, nil, other_controls))
insert(parts, "</span>")
insert(parts, get_quote(args))
insert(parts, "</div>")
local retval = concat(parts)
return deprecated and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
}) or retval
end
-- 틀에서 호출하기 위한 외부 인터페이스 ({{cite-*}} 계열 틀의 기본 인터페이스)
function export.cite_t(frame)
local parent_args = {}
for k, v in pairs(frame:getParent().args) do
parent_args[k] = v
end
local parts = {}
-- use "und" as lang if none provided
if parent_args[1] == nil then
parent_args[1] = "und"
end
local args, alias_map, other_controls = get_args(frame.args, parent_args)
-- don't nag for translations
if args.text and not args.t then
args.noreq = 1
end
local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0
if len_visible == 0 then
if not args.t or args.t == "-" then
args.nocolon = true
end
elseif args.inline == nil then
local is_block_quote = (
args.block_text or
(len_visible > 300) or
args.norm or
(args.t and args.t ~= "-" and len_visible > 80) or
(args.text and string.match(args.text, "<br>"))
)
args.inline = not is_block_quote
end
insert(parts, '<span class="citation-whole"><span class="cited-source">')
insert(parts, export.source(args, alias_map, "format_as_cite", other_controls))
insert(parts, "</span>")
local quote_content = get_quote(args, "is_cite")
if quote_content then
insert(parts, "<dl><dd>" .. quote_content .. "</dd></dl>")
end
insert(parts, "</span>")
local retval = concat(parts)
return deprecated
and frame:expandTemplate({
title = "check deprecated lang param usage",
args = {retval, lang = args.lang},
})
or retval
end
-- External interface, meant to be called from a template.
function export.call_quote_template(frame)
local parameter_sublist = {type = "parameter", sublist = true}
local iargs, other_direct_args = process_params(frame.args, {
["template"] = true,
["textparam"] = parameter_sublist,
["pageparam"] = parameter_sublist,
["propagateparams"] = parameter_sublist,
["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently.
}, true)
local function fetch_param(source, params)
for _, param in ipairs(params) do
if source[param] then
return source[param]
end
end
return nil
end
local params = {
["text"] = true,
["passage"] = true,
["footer"] = true,
["brackets"] = true,
}
local textparam = iargs.textparam or {}
for _, param in ipairs(textparam) do
params[param] = true
end
local pageparam = iargs.pageparam or {}
local pageparam1 = pageparam[1]
if pageparam1 ~= nil then
params["page"], params["pages"] = true, true
for _, param in ipairs(pageparam) do
params[param] = true
end
end
local allowparams, allow_all, list = iargs.allowparams, false
if allowparams ~= nil then
for _, allow in ipairs(allowparams) do
local param = allow:match("^(.*):list$")
if param then
if list == nil then
list = {list = true}
end
params[scribunto_parameter_key(param)] = list
elseif allow == "*" then
track("no parameter checking")
allow_all = true
else
params[scribunto_parameter_key(allow)] = true
end
end
end
local propagateparams = iargs.propagateparams or {}
for _, param in ipairs(propagateparams) do
params[param] = true
end
local parent_args = frame:getParent().args
local args = process_params(parent_args, params, allow_all)
parent_args = shallow_copy(parent_args)
if textparam[1] ~= "-" then
other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam)
end
if not (pageparam1 == nil or pageparam1 == "-") then
other_direct_args.page = fetch_param(args, pageparam) or args.page or nil
other_direct_args.pages = args.pages
end
if args.footer then
other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}}
end
if args.brackets then
other_direct_args.brackets = args.brackets
end
-- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to
-- the actual {{quote-*}} code.
if other_direct_args.authorlink == "-" then
other_direct_args.authorlink = nil
end
for _, param in ipairs(propagateparams) do
if args[param] then
other_direct_args[param] = args[param]
end
end
return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args}
end
local paramdoc_param_replacements = {
passage = {
param_with_synonym = "<<synonym>>, {{para|text}}, 또는 {{para|passage}}",
param_no_synonym = "{{para|text}} 또는 {{para|passage}}",
text = [=[
* <<params>> – 인용할 구절.]=],
},
page = {
param_with_synonym = "<<synonym>> 또는 {{para|page}}, 또는 {{para|pages}}",
param_no_synonym = "{{para|page}} 또는 {{para|pages}}",
text = "* <<params>> – '''경우에 따라 필수''': 인용된 쪽 번호. 쪽 범위를 인용할 때는 다음을 참고하세요:\n** 첫 쪽과 마지막 쪽을 엔 대시(–)로 구분하세요. 예: {{para|pages|10–11}}.\n** {{para|pageref}}를 사용하여 링크할 쪽(보통 위키낱말사전 표제어가 나오는 쪽)을 지정해야 합니다.",
},
page_with_roman_preface = {
param_with_synonym = {"inherit", "page"},
param_no_synonym = {"inherit", "page"},
text = [=[
* <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following:
** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}.
** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to the online version of the work.]=],
},
chapter = {
param_with_synonym = "<<synonym>> 또는 {{para|chapter}}",
param_no_synonym = "{{para|chapter}}",
text = "* <<params>> – 인용된 장(chapter)의 이름.",
},
roman_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in uppercase Roman numerals.]=],
},
arabic_chapter = {
param_with_synonym = {"inherit", "chapter"},
param_no_synonym = {"inherit", "chapter"},
text = [=[
* <<params>> – the chapter number quoted from in Arabic numerals.]=],
},
trailing_params = {
text = "* {{para|footer}} – 인용된 구절에 대한 주석.\n* {{para|brackets}} – 인용문을 대괄호로 묶으려면 {{para|brackets|on}}을 사용하세요. 이는 해당 인용문이 용어의 실제 사용례가 아니라 단순 언급이거나 관련 용어 정보를 제공함을 나타냅니다.",
},
}
function export.paramdoc(frame)
local parargs = frame:getParent().args
local args = process_params(parargs, {
[1] = true,
})
local text = args[1]
local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym)
local function sub_param(synonym)
local subbed_paramtext
if synonym then
subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}")
else
subbed_paramtext = paramtext_no_synonym
end
return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext))))
end
text = text:gsub("<<" .. pattern_escape(param) .. ">>", function()
return sub_param()
end)
text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param)
end
local function fetch_text(param_to_replace, key)
local spec = paramdoc_param_replacements[param_to_replace]
local val = spec[key]
if type(val) == "string" then
return val
end
if type(val) == "table" and val[1] == "inherit" then
return fetch_text(val[2], key)
end
error(
"Internal error: Unrecognized value for param '"
.. param_to_replace
.. "', key '"
.. key
.. "': "
.. mw.dumpObject(val)
)
end
for param_to_replace, spec in pairs(paramdoc_param_replacements) do
if not spec.param_no_synonym then
-- Text to substitute directly.
text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function()
return frame:preprocess(fetch_text(param_to_replace, "text"))
end)
else
do_param_with_optional_synonym(
param_to_replace,
fetch_text(param_to_replace, "text"),
fetch_text(param_to_replace, "param_with_synonym"),
fetch_text(param_to_replace, "param_no_synonym")
)
end
end
-- Remove final newline so template code can add a newline after invocation
text = text:gsub("\n$", "")
return text
end
return export