Bước tới nội dung

Khác biệt giữa bản sửa đổi của “Mô đun:Ruby”

Từ Từ nguyên Tiếng Việt
Không có tóm lược sửa đổi
Đã lùi lại sửa đổi 17974 của Admin (thảo luận)
 
Dòng 1: Dòng 1:
--- Lexicographic tools for Vietnamese language text.
local find = mw.ustring.find
 
local m_str_utils = require("Module:string utilities")
 
local find   = m_str_utils.find
local format = string.format
local gmatch = m_str_utils.gmatch
local gsub  = m_str_utils.gsub
local len    = m_str_utils.len
local match  = m_str_utils.match
local upper  = m_str_utils.upper
 
local lang  = require("Module:languages").getByCode("vi")


local p = {}
local p = {}
Dòng 20: Dòng 8:
text = text.args[1]
text = text.args[1]
end
end
return gsub(text, "%a+", function (word)
return (mw.ustring.gsub(text, "%a+", function (word)
if match(word, "^qu[yýỳỷỹỵ]$") then return word end
if mw.ustring.match(word, "^qu[yýỳỷỹỵ]$") then return word end
return gsub(word, "%a%a$", {
return (mw.ustring.gsub(word, "%a%a$", {
["oá"] = "óa", ["oà"] = "òa", ["oả"] = "ỏa", ["oã"] = "õa", ["oạ"] = "ọa",
["oá"] = "óa", ["oà"] = "òa", ["oả"] = "ỏa", ["oã"] = "õa", ["oạ"] = "ọa",
["oé"] = "óe", ["oè"] = "òe", ["oẻ"] = "ỏe", ["oẽ"] = "õe", ["oẹ"] = "ọe",
["oé"] = "óe", ["oè"] = "òe", ["oẻ"] = "ỏe", ["oẽ"] = "õe", ["oẹ"] = "ọe",
["uý"] = "úy", ["uỳ"] = "ùy", ["uỷ"] = "ủy", ["uỹ"] = "ũy", ["uỵ"] = "ụy"
["uý"] = "úy", ["uỳ"] = "ùy", ["uỷ"] = "ủy", ["uỹ"] = "ũy", ["uỵ"] = "ụy"
})
}))
end)
end))
end
end


Dòng 35: Dòng 23:
text = text.args[1]
text = text.args[1]
end
end
return gsub(text, "%a+", function (word)
return (mw.ustring.gsub(text, "%a+", function (word)
return gsub(word, "%a%a$", {
return (mw.ustring.gsub(word, "%a%a$", {
["óa"] = "oá", ["òa"] = "oà", ["ỏa"] = "oả", ["õa"] = "oã", ["ọa"] = "oạ",
["óa"] = "oá", ["òa"] = "oà", ["ỏa"] = "oả", ["õa"] = "oã", ["ọa"] = "oạ",
["óe"] = "oé", ["òe"] = "oè", ["ỏe"] = "oẻ", ["õe"] = "oẽ", ["ọe"] = "oẹ",
["óe"] = "oé", ["òe"] = "oè", ["ỏe"] = "oẻ", ["õe"] = "oẽ", ["ọe"] = "oẹ",
["úy"] = "uý", ["ùy"] = "uỳ", ["ủy"] = "uỷ", ["ũy"] = "uỹ", ["ụy"] = "uỵ"
["úy"] = "uý", ["ùy"] = "uỳ", ["ủy"] = "uỷ", ["ũy"] = "uỹ", ["ụy"] = "uỵ"
})
}))
end)
end))
end
end


Dòng 51: Dòng 39:
main_spelling, makeLinks = frame.args[1], frame.args.link
main_spelling, makeLinks = frame.args[1], frame.args.link
end
end
 
local xformers = {
local xformers = {
p.toTraditionalTones,
p.toTraditionalTones, p.toReformedTones,
p.toReformedTones,
}
}
 
local spellings = {}
local spellings = {}
for _, xformer in ipairs(xformers) do
for i, xformer in ipairs(xformers) do
local alt_spelling = xformer(main_spelling)
local alt_spelling = xformer(main_spelling)
if not spellings[alt_spelling] then
if not spellings[alt_spelling] then
Dòng 65: Dòng 52:
end
end
end
end
 
if makeLinks then
if makeLinks then
local m_links = require("Module:links")
local m_links = require("Module:links") -- [[Module:links]]
for k, link in ipairs(spellings) do
for k, link in ipairs(spellings) do
spellings[k] = m_links.full_link({lang = lang, term = link})
spellings[k] = m_links.full_link({lang = lang, term = link})
end
end
end
end
return frame and table.concat(spellings, "/") or spellings
return frame and table.concat(spellings, "/") or spellings
end
end


---Unicode codepoints for combining Vietnamese tone marks.
---Unicode codepoints for combining Vietnamese tone marks.
p.combiningToneMarks = mw.ustring.char(0x300, 0x301, 0x303, 0x309, 0x323)
p.combiningToneMarks = mw.ustring.char(
0x300, -- à
0x301, -- á
0x303, -- ã
0x309, -- ả
0x323 -- ạ
)


---Unicode codepoints for combining Vietnamese accent marks.
---Unicode codepoints for combining Vietnamese accent marks.
p.combiningAccentMarks = mw.ustring.char(0x302, 0x306, 0x31b)
p.combiningAccentMarks = mw.ustring.char(
0x302, -- â
0x306, -- ă
0x31b -- ơ
)


---Strips Vietnamese diacritical marks from the given text.
---Strips Vietnamese diacritical marks from the given text.
-- @param tones  Set to “0” to leave tone marks intact.
-- @param accents  Set to “0” to leave accent marks intact.
-- @param đ    Set to “0” to leave “Đ” and “đ” intact.
function p.removeDiacritics(text, toneMarks, accentMarks, stroke)
function p.removeDiacritics(text, toneMarks, accentMarks, stroke)
if type(text) == "table" then
if type(text) == "table" then
Dòng 90: Dòng 89:
not text.args["đ"] or tonumber(text.args["đ"]) == 1
not text.args["đ"] or tonumber(text.args["đ"]) == 1
end
end
text = mw.ustring.toNFD(text)
text = mw.ustring.toNFD(text)
if toneMarks then
if toneMarks then
text = gsub(text, "[" .. p.combiningToneMarks .. "]", "")
text = mw.ustring.gsub(text, "[" .. p.combiningToneMarks .. "]", "")
end
end
if accentMarks then
if accentMarks then
text = gsub(text, "[" .. p.combiningAccentMarks .. "]", "")
text = mw.ustring.gsub(text, "[" .. p.combiningAccentMarks .. "]", "")
end
end
if stroke then
if stroke then
text = gsub(text, "[Đđ]", {["Đ"] = "D", ["đ"] = "d"})
text = mw.ustring.gsub(text, "[Đđ]", {["Đ"] = "D", ["đ"] = "d"})
end
end
return mw.ustring.toNFC(text)
return mw.ustring.toNFC(text)
end
end
Dòng 111: Dòng 107:
---Compare two syllables according to Vietnamese dictionary sorting order.
---Compare two syllables according to Vietnamese dictionary sorting order.
function p.compWord(word1, word2)
function p.compWord(word1, word2)
if find(word1, word2, 1, true) == 1 then return false end
if mw.ustring.find(word1, word2, 1, true) == 0 then return false end
if find(word2, word1, 1, true) == 1 then return true end
if mw.ustring.find(word2, word1, 1, true) == 0 then return true end
 
local iter1 = gmatch(word1, "[" .. p.letters .. "]")
do
local iter2 = gmatch(word2, "[" .. p.letters .. "]")
local func1, static1, var1 = mw.ustring.gmatch(word1, "[" .. p.letters .. "]")
 
local func2, static2, var2 = mw.ustring.gmatch(word2, "[" .. p.letters .. "]")
while true do
while true do
local c1 = iter1()
local c1 = func1(static1, var1)
local c2 = iter2()
local c2 = func2(static2, var2)
if c1 == nil or c2 == nil then break end
if c1 == nil or c2 == nil then break end
 
local idx1 = find(p.letters, c1, 1, true)
local idx1 = mw.ustring.find(p.letters, c1, 1, true)
local idx2 = find(p.letters, c2, 1, true)
local idx2 = mw.ustring.find(p.letters, c2, 1, true)
 
if idx1 and idx2 then
if idx1 and idx2 then
if idx1 < idx2 then return true end
if idx1 < idx2 then return true end
if idx1 > idx2 then return false end
if idx1 > idx2 then return false end
end
end
end
end
end
 
return word1 < word2
return word1 < word2
end
end


---Abbreviations and text for Han tu references.
---Abbreviations and text for Han tu references (used by p.createRefTag())
---[[Wiktionary:Beer parlour/2018/December#References for Vietnamese readings listed under Template:vi-readings]]
p.refAbbreviations = {
p.refAbbreviations = {
tvctdhv = "Trần (1999)",
tvctdhv = "Trần (1999)";
hvttd   = "Nguyễn (1974)",
hvttd = "Nguyễn (1974)";
vntd   = "Văn Mới (1954)",
vntd = "Văn Mới (1954)";
tchvtd = "Thiều Chửu (1942)",
tchvtd = "Thiều Chửu (1942)";
tdcndg = "Nguyễn (2014)",
tdcndg = "Nguyễn (2014)",
tdcntd = "Nguyễn et al. (2009)",
tdcntd = "Nguyễn et al. (2009)",
gdhn   = "Trần (2004)",
gdhn = "Trần (2004)",
dtdcn   = "Vũ (1998)",
dtdcn = "Vũ (1998)",
btcn   = "Hồ (1976)",
btcn = "Hồ (1976)",
bonet   = "Bonet (1899)",
bonet = "Bonet (1899)",
genibrel= "Génibrel (1898)",
genibrel = "Génibrel (1898)",
taberd = "Taberd & Pigneau de Béhaine (1838)",
taberd = "Taberd & Pigneau de Béhaine (1838)",
}
}


---Creates a ref tag containing [[Template:vi-ref]].
---Creates a ref tag containing [[Template:vi-ref]].
---Expands abbreviations using p.refAbbreviations.
function p.createRefTag(ref)
function p.createRefTag(ref)
local refFullName = p.refAbbreviations[ref] or ref
local refFullName = p.refAbbreviations[ref] or ref
return mw.getCurrentFrame():extensionTag{
return mw.getCurrentFrame():extensionTag{
name = "ref",
name = "ref",
args = { name = ref },
args = {
content = format("{{vi-ref|%s.}}", refFullName)
name = ref,
},
content = mw.ustring.format("{{vi-ref|%s.}}", refFullName),
}
}
end
end
Dòng 162: Dòng 162:
---[[Template:vi-readings]]
---[[Template:vi-readings]]
function p.readings(hanviet, nom, rs, phienthiet, reading)
function p.readings(hanviet, nom, rs, phienthiet, reading)
local pagename = mw.loadData("Module:headword/data").pagename
local pagename = mw.title.getCurrentTitle().text
 
if type(hanviet) == "table" then
if type(hanviet) == "table" then
local args = hanviet:getParent().args
local args = hanviet:getParent().args
Dòng 170: Dòng 169:
args.phienthiet or args.phth or args.fanqie, args.reading or args.readings
args.phienthiet or args.phth or args.fanqie, args.reading or args.readings
end
end
 
local lines = {}
local lines = {}
local styles = {
local styles = {
{
{
link = "Hán Việt",
link = "Hán Việt",
cat = "Vietnamese Chữ Hán",
cat = "Vietnamese Han tu",
list = hanviet and mw.text.split(hanviet, "%s*,%s*"),
list = hanviet and mw.text.split(hanviet, "%s*,%s*"),
phienthiet = phienthiet and mw.text.split(phienthiet, "%s*,%s*")
phienthiet = phienthiet and mw.text.split(phienthiet, "%s*,%s*")
Dòng 190: Dòng 189:
},
},
}
}
 
for i, style in ipairs(styles) do
for _, style in ipairs(styles) do
if style.list and #style.list > 0 and #style.list[1] > 0 then
if style.list and #style.list > 0 and #style.list[1] > 0 then
local readings = style.list
local readings = style.list
-- table.sort(readings, p.comp)
for j, reading in ipairs(readings) do


for j, reading in ipairs(readings) do
local ref
local ref
local a, b = match(reading, "(.-)%s*%-%s*(.+)")
local a, b = mw.ustring.match(reading, "(.-)%s*%-%s*(.+)")
if a then
if a then
reading, ref = a, b
reading, ref = a, b
Dòng 204: Dòng 203:
local spellings = p.allSpellings(reading, true)
local spellings = p.allSpellings(reading, true)
readings[j] = table.concat(spellings, "/")
readings[j] = table.concat(spellings, "/")
 
-- Linking of "切" to "fanqie"
-- Linking of "切" to "fanqie" for English explanation
if style.phienthiet and style.phienthiet[j] then
if style.phienthiet and style.phienthiet[j] then
local pruby = "link"
pruby = "link"
local ruby = p.ruby(match(mw.text.trim(style.phienthiet[j]), "(%a+) +(.+)"))
local ruby = p.ruby(mw.ustring.match(mw.text.trim(style.phienthiet[j]),
"(%a+) +(.+)"))
pruby = {}
if ruby then
if ruby then
pruby = "nocolor"
pruby = "nocolor"
local suffix = p.ruby("切", "thiết")
local suffix = p.ruby("切", "thiết")
readings[j] = format("%s (%s[[fanqie#English|%s]])", readings[j], ruby, suffix)
pruby = {}
readings[j] = mw.ustring.format("%s (%s[[fanqie#English|%s]])",
readings[j], ruby, suffix)
end
end
end
end
Dòng 218: Dòng 221:
-- References
-- References
if ref then
if ref then
for r in mw.text.gsplit(ref, "%s*;%s*") do
for ref in mw.text.gsplit(ref, "%s*;%s*") do
readings[j] = readings[j] .. p.createRefTag(r)
readings[j] = readings[j] .. p.createRefTag(ref)
end
end
end
end
end
end
if #readings > 0 then
if #readings > 0 then
local sortkey = rs or pagename
local sortkey = rs or mw.title.getCurrentTitle().text
readings = table.concat(readings, ", ")
readings = table.concat(readings, ", ")
table.insert(lines, format(
table.insert(lines, mw.ustring.format("<span class='Hani' lang='vi' style='font-size: 120%%;font-style: normal!important;'>%s</span>: '''[[%s]]''' readings: %s[[Category:%s|%s]] [[Category:Vietnamese lemmas]] [[Category:Vietnamese Han characters]]</br>",
"<span class='Hani' lang='vi' style='font-size: 135%%;'>%s</span>: '''[[%s]]''' readings: %s[[Category:%s|%s]] [[Category:Vietnamese lemmas]] [[Category:Vietnamese Han characters]]</br>",
pagename, style.link, readings, style.cat, sortkey))
pagename, style.link, readings, style.cat, sortkey))
end
end
end
end
end
end
 
return table.concat(lines, "\n")
return table.concat(lines, "\n")
end
end


---[[Template:vi-ruby]]
---[[Template:vi-ruby]]
local pruby = {}  -- shared state used by readings() and ruby()
function p.ruby(characters, readings, mark, alts)
function p.ruby(characters, readings, mark, alts)
if type(characters) == "table" then
if type(characters) == "table" then
Dòng 246: Dòng 245:
args[1] or "",
args[1] or "",
args[2] or "",
args[2] or "",
args.mark or mw.loadData("Module:headword/data").pagename,
args.mark or mw.title.getCurrentTitle().text,
((args.alts and mw.text.split(args.alts, "%s+")) or
((args.alts and mw.text.split(args.alts, "%s+")) or
(args.ids and mw.text.split(args.ids, "%s+")) or {})
(args.ids and mw.text.split(args.ids, "%s+")) or {})
end
end
 
if not readings then
if not readings then
return characters
return characters
end
end
 
readings = mw.text.split(readings, "[^" .. p.letters .. "]+")
readings = mw.text.split(readings, "[^" .. p.letters .. "]+")
local result = {}
local result = {}
local character_idx = 1
local character_idx = 1
local alt_idx = 1
local alt_idx = 1
 
for character in mw.ustring.gmatch(characters, ".") do
for character in gmatch(characters, ".") do
local is_alt = false
local is_alt = false
if character == "*" and alts[alt_idx] then
if character == "*" and alts[alt_idx] then
Dòng 267: Dòng 266:
alt_idx = alt_idx + 1
alt_idx = alt_idx + 1
end
end
 
if is_alt or (mw.ustring.match(character, "^%a$") and not character:match("^%w$")) then
if is_alt or (match(character, "^%a$") and not character:match("^%w$")) then
local reading = readings[character_idx]
local reading = readings[character_idx]
if mark and character == mark then
if mark and character == mark then
character = format("<mark>%s</mark>", character)
character = mw.ustring.format("<mark>%s</mark>", character)
reading = format("<mark>%s</mark>", reading)
reading = mw.ustring.format("<mark>%s</mark>", reading)
end
end
if pruby == 'link' then
if pruby == 'link' then
character = format(
character = mw.ustring.format(
"<ruby><rb><span class='Hani' style='font-size: 100%%'>[[%s#Vietnamese|%s]]</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 135%%;'>[[%s#Vietnamese|%s]]</span></rt><rp>)</rp></ruby>",
"<ruby><rb><span class='Hani'; span style='font-size: 100%%'>[[%s#Vietnamese|%s]]</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 120%%;'>[[%s#Vietnamese|%s]]</span></rt><rp>)</rp></ruby>",
character, character, reading, reading)
character, character, reading, reading)
elseif pruby == 'nocolor' then
end
character = format(
if pruby == 'nocolor' then
"<ruby><rb><span class='Hani' style='color:#202122;'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 125%%;'>%s</span></rt><rp>)</rp></ruby>",
character = mw.ustring.format(
"<ruby><rb><span class='Hani' style='color:#000000;'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 120%%;'>%s</span></rt><rp>)</rp></ruby>",
character, reading)
character, reading)
else
end
character = format(
if pruby ~= 'link' and pruby ~= 'nocolor' then
character = mw.ustring.format(
"<ruby><rb><span class='Hani'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em;'>%s</span></rt><rp>)</rp></ruby>",
"<ruby><rb><span class='Hani'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em;'>%s</span></rt><rp>)</rp></ruby>",
character, reading)
character, reading)
end
end
character_idx = character_idx + 1
character_idx = character_idx + 1
end
end
table.insert(result, character)
table.insert(result, character)
end
end
 
return mw.ustring.format("<span lang='vi' style='font-size: 120%%;font-style: normal!important;'>%s</span>", table.concat(result))
return format("<span lang='vi' style='font-size: 135%%;'>%s</span>", table.concat(result))
end
end


function p.hantutab()
function p.hantutab()
local hantu = gsub(mw.loadData("Module:headword/data").pagename, '[^一-鿿㐀-䶿﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧-﨩𠀀-𪛟𪜀-𮯯𰀀-𱍏]', '')
local hantu = mw.ustring.gsub(mw.title.getCurrentTitle().text, '[^一-鿿㐀-䶿﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧-﨩𠀀-𪛟𪜀-𮯯𰀀-𱍏]', '')
local table_head = '<table class="floatright wikitable" style="text-align:center; font-size:small;"><tr><th colspan="' ..
local table_head = '<table class="floatright wikitable" style="text-align:center; font-size:small;"><tr><th colspan="' ..  
len(hantu) ..
mw.ustring.len(hantu) ..  
'" style="font-weight:normal;">[[Hán tự]] in this term</th></tr><tr lang="vi" class="Hani" style="font-size:2em; background:white; line-height:1em;">'
'" style="font-weight:normal;">[[Hán tự]] in this term</th></tr><tr lang="vi" class="Hani" style="font-size:2em; background:white; line-height:1em;">'
 
return table_head ..  
return table_head ..
mw.ustring.gsub(hantu, '(.)', '<td style="padding:0.5em;">[[%1#Vietnamese|%1]]</td>') ..  
gsub(hantu, '(.)', '<td style="padding:0.5em;">[[%1#Vietnamese|%1]]</td>') ..
'</tr></table>'
'</tr></table>'
end
end
Dòng 313: Dòng 308:
local src = frame.args[1]
local src = frame.args[1]
local classifiers = {}
local classifiers = {}
for classifier in gmatch(gsub(src, "<[^>]->", ""), "[" .. p.letters .. "]+") do
for classifier in mw.ustring.gmatch(mw.ustring.gsub(src, "<[^>]->", ""), "[" .. p.letters .. "]+") do
if classifier ~= "l" and classifier ~= "vi" and classifier ~= "vi-l" and
if classifier ~= "l" and classifier ~= "vi" and classifier ~= "vi-l" and
  classifier ~= "Vietnamese" then
classifier ~= "Vietnamese" then
local cat = format("[[Category:Vietnamese nouns classified by %s]]", classifier)
local cat = mw.ustring.format("[[Category:Vietnamese nouns classified by %s]]",
classifier)
table.insert(classifiers, cat)
table.insert(classifiers, cat)
end
end
Dòng 324: Dòng 320:


function p.new(frame)
function p.new(frame)
local title = mw.loadData("Module:headword/data").pagename
local title = mw.title.getCurrentTitle().subpageText
local args = frame:getParent().args
local args = frame:getParent().args
local pos = args[1] or ""
local pos = args[1] or ""
Dòng 335: Dòng 331:
local head = args["head"] or false
local head = args["head"] or false
local cat = args["cat"] or false
local cat = args["cat"] or false
local reg = args["reg"] or false
local cls = args["cls"] or false
local cls = args["cls"] or false
local rdp = args["rdp"] or false
local rdp = args["rdp"] or false
Dòng 340: Dòng 337:
local pic = args["pic"] or false
local pic = args["pic"] or false
local picc = args["picc"] or false
local picc = args["picc"] or false
 
nom = nom and gsub(nom, "(.)", "[[%1]], ") or false
nom = nom and mw.ustring.gsub(nom, "(.)", "[[%1]], ") or false
nom = nom and gsub(nom, ", $", "") or false
nom = nom and mw.ustring.gsub(nom, ", $", "") or false
 
if args["h"] then
if args["h"] then
etym = "{{vi-etym-sino|" .. args["h"] .. "}}."
etym = "{{vi-etym-sino|" .. args["h"] .. "}}."
end
end
 
if not etym and mw.ustring.match(title, " ") then
if not etym and match(title, " ") then
etym = "{{com|vi"
etym = "{{com|vi"
for word in mw.text.gsplit(title, " ") do
for word in mw.text.gsplit(title, " ") do
Dòng 355: Dòng 350:
etym = etym .. "}}."
etym = etym .. "}}."
end
end
if etym == "-" then etym = false end
if etym == "-" then etym = false end
if etym then etym = gsub(etym, "^%<", "From") end
if etym then etym = mw.ustring.gsub(etym, "^%<", "From") end
 
local result = ""
local result = ""
 
local function genTitle(text)
local function genTitle(text)
local pos_title = {
local pos_title = {
Dòng 367: Dòng 361:
["prep"] = "Preposition", ["postp"] = "Postposition", ["conj"] = "Conjunction",
["prep"] = "Preposition", ["postp"] = "Postposition", ["conj"] = "Conjunction",
["part"] = "Particle", ["suf"] = "Suffix",
["part"] = "Particle", ["suf"] = "Suffix",
["prov"] = "Proverb", ["id"] = "Idiom", ["ph"] = "Phrase", ["intj"] = "Interjection",
["prov"] = "Proverb", ["id"] = "Idiom", ["ph"] = "Phrase", ["intj"] = "Interjection", ["interj"] = "Interjection",
["cl"] = "Classifier", ["cls"] = "Classifier", ["num"] = "Numeral", ["abb"] = "Abbreviation", ["deter"] = "Determiner"
["cl"] = "Classifier", ["cls"] = "Classifier", ["num"] = "Numeral", ["abb"] = "Abbreviation", ["deter"] = "Determiner"
}
};
return pos_title[text] or upper(text:sub(1,1)) .. text:sub(2)
return pos_title[text] or mw.ustring.upper(sub(text, 1, 1)) .. sub(text, 2, -1)
end
end
 
local function genHead(text)
local function genHead(text)
local pos_head = {
local pos_head = {
[""] = "noun", ["n"] = "noun", ["pn"] = "proper noun", ["propn"] = "proper noun",
[""] = "noun", ["n"] = "noun", ["pn"] = "proper noun", ["propn"] = "proper noun", ["v"] = "verb", ["vf"] = "verb form", ["a"] = "adj",
["v"] = "verb", ["vf"] = "verb form", ["a"] = "adj",
["postp"] = "post", ["conj"] = "conj", ["part"] = "particle", ["pron"] = "pronoun",
["postp"] = "post", ["conj"] = "conj", ["part"] = "particle", ["pron"] = "pronoun",
["prov"] = "proverb", ["id"] = "idiom", ["ph"] = "phrase", ["intj"] = "interj",
["prov"] = "proverb", ["id"] = "idiom", ["ph"] = "phrase", ["intj"] = "interj",
["abb"] = "abbr", ["cl"] = "classifier", ["deter"] = "det"
["abb"] = "abbr", ["cl"] = "classifier", ["deter"] = "det"
}
};
return pos_head[text] or text
return pos_head[text] or text
end
end
 
local function other(class, title, args)
local function other(class, title, args)
local code = ""
local code = ""
local i = 2
if class == "der" and args[class] then
if class == "der" and args[class] then
code = code .. "\n\n===" .. title .. "===\n{{col3|vi|" .. args[class]
code = code .. "\n\n===" .. title .. "===\n{{col3|vi|" .. args[class]
i = 2
while args[class .. i] do
while args[class .. i] do
code = code .. "|" .. args[class .. i]
code = code .. "|" .. args[class .. i]
Dòng 396: Dòng 389:
elseif args[class] then
elseif args[class] then
code = code .. "\n\n===" .. title .. "===\n* {{l|vi|" .. args[class] .. "}}"
code = code .. "\n\n===" .. title .. "===\n* {{l|vi|" .. args[class] .. "}}"
i = 2
while args[class .. i] do
while args[class .. i] do
code = code .. "\n* {{l|vi|" .. args[class .. i] .. "}}"
code = code .. "\n* {{l|vi|" .. args[class .. i] .. "}}"
Dòng 403: Dòng 398:
return code
return code
end
end
 
result = result .. "==Vietnamese=="
result = result .. "==Vietnamese=="
if args["wp"] then
if args["wp"] then result = result .. "\n{{wikipedia|lang=vi" ..  
result = result .. "\n{{wp|vi:" .. (args["wp"] == "y" and "" or args["wp"]) .. "}}"
(args["wp"] == "y" and "" or "|" .. args["wp"]) .. "}}" end
end
if pic then result = result .. "\n[[File:" .. pic .. "|thumb|" ..  
if pic then
(picc or mw.ustring.gsub(title, '^%l', mw.ustring.upper) .. ".") .. "]]" end
result = result .. "\n[[File:" .. pic .. "|thumb|" .. (picc or upper(title:sub(1,1)) .. title:sub(2) .. ".") .. "]]"
end
 
result = result .. other("alt", "Alternative forms", args)
result = result .. other("alt", "Alternative forms", args)
if etym then result = result .. "\n\n===Etymology===\n" .. etym end
if etym then result = result .. "\n\n===Etymology===\n" .. etym end
result = result .. "\n\n===Pronunciation===\n{{vi-IPA}}"
result = result .. "\n\n===Pronunciation===\n{{vi-IPA}}"
result = result .. "\n\n===" .. genTitle(pos) .. "===\n{{vi-" .. genHead(pos) ..
result = result .. "\n\n===" .. genTitle(pos) .. "===\n{{vi-" .. genHead(pos) .. (head and ("|head=" .. head) or "") ..  
(head and ("|head=" .. head) or "") ..
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..  
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..
(((genHead(pos) == "adj" or genHead(pos) == "verb" or genHead(pos) == "adv") and rdp) and "|rdp=" .. rdp or "") ..  
(((genHead(pos) == "adj" or genHead(pos) == "verb" or genHead(pos) == "adv") and rdp) and "|rdp=" .. rdp or "") ..
(nom and "|" .. nom or "") ..  
(nom and "|" .. nom or "") ..
"}}\n\n# " .. def
"}}\n\n# " .. def
 
result = result .. other("syn", "=Synonyms=", args)
result = result .. other("syn", "=Synonyms=", args)
result = result .. other("ant", "=Antonyms=", args)
result = result .. other("ant", "=Antonyms=", args)
result = result .. other("der", "=Derived terms=", args)
result = result .. other("der", "=Derived terms=", args)
result = result .. other("also", "=See also=", args)
result = result .. other("also", "=See also=", args)
 
if pos2 then
if pos2 then
result = result .. "\n\n===" .. genTitle(pos2) .. "===\n{{vi-" .. genHead(pos2) ..
result = result .. "\n\n===" .. genTitle(pos2) .. "===\n{{vi-" .. genHead(pos2) .. (head and ("|head=" .. head) or "") ..  
(head and ("|head=" .. head) or "") ..
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..  
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..
(((genHead(pos2) == "adj" or genHead(pos2) == "verb" or genHead(pos2) == "adv") and rdp) and "|rdp=" .. rdp or "") ..  
(((genHead(pos2) == "adj" or genHead(pos2) == "verb" or genHead(pos2) == "adv") and rdp) and "|rdp=" .. rdp or "") ..
(nom and "|" .. nom or "") ..  
(nom and "|" .. nom or "") ..
"}}\n\n# " .. def2
"}}\n\n# " .. def2
end
end
 
if pos3 then
if pos3 then
result = result .. "\n\n===" .. genTitle(pos3) .. "===\n{{vi-" .. genHead(pos3) ..
result = result .. "\n\n===" .. genTitle(pos3) .. "===\n{{vi-" .. genHead(pos3) .. (head and ("|head=" .. head) or "") ..  
(head and ("|head=" .. head) or "") ..
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..  
((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") ..
(((genHead(pos3) == "adj" or genHead(pos3) == "verb" or genHead(pos3) == "adv") and rdp) and "|rdp=" .. rdp or "") ..  
(((genHead(pos3) == "adj" or genHead(pos3) == "verb" or genHead(pos3) == "adv") and rdp) and "|rdp=" .. rdp or "") ..
(nom and "|" .. nom or "") ..  
(nom and "|" .. nom or "") ..
"}}\n\n# " .. def3
"}}\n\n# " .. def3
end
end
 
if cat then result = result .. "\n\n{{C|vi|" .. cat .. "}}" end
if cat then result = result .. "\n\n{{C|vi|" .. cat .. "}}" end
 
return result
return result
end
end


function p.new_der(frame)
function p.new_der(frame)
local title = mw.loadData("Module:headword/data").pagename
local title = mw.title.getCurrentTitle().subpageText
local data_module = require("Module:vi/vocab-list")
local data_module = require("Module:vi/vocab-list")
local args = frame:getParent().args
local args = frame:getParent().args
local result = {}
local result = {}
for _, arg in ipairs(args) do
for _, arg in ipairs(args) do
table.insert(result, arg)
table.insert(result, arg)
end
end
 
for _, word in ipairs(data_module) do
for _, word in ipairs(data_module) do
if find(word, title) and word ~= title and not find(word, title .. "[^ ]") and not find(word, "[^ ]" .. title) then
if find(word, title) and word ~= title and not find(word, title .. "[^ ]") and not find(word, "[^ ]" .. title) then
Dòng 465: Dòng 455:
end
end
end
end
 
local hash, res = {}, {}
local hash, res = {}, {}
for _, element in ipairs(result) do
for _, element in ipairs(result) do
Dòng 473: Dòng 463:
end
end
end
end
 
local vi_sort_module = require("Module:vi-sortkey")
local vi_sort_module = require("Module:vi-sortkey")
local makeSortKey = require("Module:memoize")(vi_sort_module.makeSortKey)
local makeSortKey = require("Module:fun").memoize(vi_sort_module.makeSortKey)
 
table.sort(res, function(term1, term2) return makeSortKey(term1) < makeSortKey(term2) end)
table.sort(res, function(term1, term2)
return makeSortKey(term1) < makeSortKey(term2)
end)
 
return "{{vi-der|" .. table.concat(res, "|") .. "}}"
return "{{vi-der|" .. table.concat(res, "|") .. "}}"
end
end
Dòng 487: Dòng 474:
local tu_lay_note = "<span style=\"padding-left:4px; padding-right:4px\">&nbsp;</span><span style=\"background:#ffffe0\">(''[[từ láy]]'')</span>"
local tu_lay_note = "<span style=\"padding-left:4px; padding-right:4px\">&nbsp;</span><span style=\"background:#ffffe0\">(''[[từ láy]]'')</span>"
local m_columns = require("Module:columns")
local m_columns = require("Module:columns")
local lang = require("Module:languages").getByCode("vi")
local m_links = require("Module:links")
local m_links = require("Module:links")
local args = frame:getParent().args
local args = frame:getParent().args
local pagename = mw.loadData("Module:headword/data").pagename
local pagename = mw.title.getCurrentTitle().text
local result = {}
local result = {}
local length = 0
local length = 0
unfold = args["unfold"] and true or false
title = args["title"] or false
title_text = title or "Derived terms"


local unfold = args["unfold"] and true or false
for i, word in ipairs(args) do
local title = args["title"] or false
word, is_tu_lay = mw.ustring.gsub(word, "%:tl", "")
local title_text = title or "Derived terms"
tu_lay = is_tu_lay > 0 and tu_lay_note or ""
 
local word_parts = mw.text.split(mw.ustring.gsub(word, "\n", "" ), ":")
for _, word in ipairs(args) do
table.insert(result, m_links.full_link({  
local w, is_tu_lay = gsub(word, "%:tl", "")
lang = lang,  
local tu_lay = is_tu_lay > 0 and tu_lay_note or ""
term = word_parts[1],  
local word_parts = mw.text.split(gsub(w, "\n", ""), ":")
gloss = word_parts[2] or nil }) ..
table.insert(result, m_links.full_link({
lang = lang,
tu_lay)
term = word_parts[1],
gloss = word_parts[2] or nil
length = math.max(mw.ustring.len(word), length)
}) .. tu_lay)
length = math.max(len(w), length)
end
end
 
return m_columns.create_list {
return  
column_count = (length > 15 and 2 or 3),
m_columns.create_table(
content = result,
(length > 15 and 2 or 3),  
header = "''(" .. title_text .. ")'':",
result,  
alphabetize = true,
1,
collapse = (unfold or #result < 7) and false or true,
"#F5F5FF",
class = "columns-bg",
((unfold or #result < 7) and false or true),  
lang = lang
"Derived terms",
}
title_text,
nil,
nil,
lang
)
end
end


return p
return p

Bản mới nhất lúc 16:39, ngày 31 tháng 3 năm 2026

Có thể viết tài liệu về mô đun này tại Mô đun:Ruby/tài liệu.

local find = mw.ustring.find

local p = {}

---Converts the given text to traditional tone marks.
function p.toTraditionalTones(text)
	if type(text) == "table" then
		text = text.args[1]
	end
	return (mw.ustring.gsub(text, "%a+", function (word)
		if mw.ustring.match(word, "^qu[yýỳỷỹỵ]$") then return word end
		return (mw.ustring.gsub(word, "%a%a$", {
			["oá"] = "óa", ["oà"] = "òa", ["oả"] = "ỏa", ["oã"] = "õa", ["oạ"] = "ọa",
			["oé"] = "óe", ["oè"] = "òe", ["oẻ"] = "ỏe", ["oẽ"] = "õe", ["oẹ"] = "ọe",
			["uý"] = "úy", ["uỳ"] = "ùy", ["uỷ"] = "ủy", ["uỹ"] = "ũy", ["uỵ"] = "ụy"
		}))
	end))
end

---Converts the given text to reformed tone marks.
function p.toReformedTones(text)
	if type(text) == "table" then
		text = text.args[1]
	end
	return (mw.ustring.gsub(text, "%a+", function (word)
		return (mw.ustring.gsub(word, "%a%a$", {
			["óa"] = "oá", ["òa"] = "oà", ["ỏa"] = "oả", ["õa"] = "oã", ["ọa"] = "oạ",
			["óe"] = "oé", ["òe"] = "oè", ["ỏe"] = "oẻ", ["õe"] = "oẽ", ["ọe"] = "oẹ",
			["úy"] = "uý", ["ùy"] = "uỳ", ["ủy"] = "uỷ", ["ũy"] = "uỹ", ["ụy"] = "uỵ"
		}))
	end))
end

---Generate alternative orthographies.
function p.allSpellings(main_spelling, makeLinks)
	local frame = nil
	if type(main_spelling) == "table" then
		frame = main_spelling
		main_spelling, makeLinks = frame.args[1], frame.args.link
	end
	
	local xformers = {
		p.toTraditionalTones, p.toReformedTones,
	}
	
	local spellings = {}
	for i, xformer in ipairs(xformers) do
		local alt_spelling = xformer(main_spelling)
		if not spellings[alt_spelling] then
			table.insert(spellings, alt_spelling)
			spellings[alt_spelling] = true
		end
	end
	
	if makeLinks then
		local m_links = require("Module:links") -- [[Module:links]]
		for k, link in ipairs(spellings) do
			spellings[k] = m_links.full_link({lang = lang, term = link})
		end
	end
	return frame and table.concat(spellings, "/") or spellings
end

---Unicode codepoints for combining Vietnamese tone marks.
p.combiningToneMarks = mw.ustring.char(
	0x300, -- à
	0x301, -- á
	0x303, -- ã
	0x309, -- ả
	0x323  -- ạ
)

---Unicode codepoints for combining Vietnamese accent marks.
p.combiningAccentMarks = mw.ustring.char(
	0x302, -- â
	0x306, -- ă
	0x31b  -- ơ
)

---Strips Vietnamese diacritical marks from the given text.
-- @param tones   Set to “0” to leave tone marks intact.
-- @param accents  Set to “0” to leave accent marks intact.
-- @param đ     Set to “0” to leave “Đ” and “đ” intact.
function p.removeDiacritics(text, toneMarks, accentMarks, stroke)
	if type(text) == "table" then
		text, toneMarks, accentMarks, stroke = text.args[1],
			not text.args.tones or tonumber(text.args.tones) == 1,
			not text.args.accents or tonumber(text.args.accents) == 1,
			not text.args["đ"] or tonumber(text.args["đ"]) == 1
	end
	text = mw.ustring.toNFD(text)
	if toneMarks then
		text = mw.ustring.gsub(text, "[" .. p.combiningToneMarks .. "]", "")
	end
	if accentMarks then
		text = mw.ustring.gsub(text, "[" .. p.combiningAccentMarks .. "]", "")
	end
	if stroke then
		text = mw.ustring.gsub(text, "[Đđ]", {["Đ"] = "D", ["đ"] = "d"})
	end
	return mw.ustring.toNFC(text)
end

---Vietnamese letters for use in comp().
p.letters = "aAàÀảẢãÃáÁạẠăĂằẰẳẲẵẴắẮặẶâÂầẦẩẨẫẪấẤậẬbBcCdDđĐeEèÈẻẺẽẼéÉẹẸêÊềỀểỂễỄếẾệỆfFgGhHiIìÌỉỈĩĨíÍịỊjJkKlLmMnNoOòÒỏỎõÕóÓọỌôÔồỒổỔỗỖốỐộỘơƠờỜởỞỡỠớỚợỢpPqQrRsStTuUùÙủỦũŨúÚụỤưƯừỪửỬữỮứỨựỰvVwWxXyYỳỲỷỶỹỸýÝỵỴzZ"

---Compare two syllables according to Vietnamese dictionary sorting order.
function p.compWord(word1, word2)
	if mw.ustring.find(word1, word2, 1, true) == 0 then return false end
	if mw.ustring.find(word2, word1, 1, true) == 0 then return true end
	
	do
		local func1, static1, var1 = mw.ustring.gmatch(word1, "[" .. p.letters .. "]")
		local func2, static2, var2 = mw.ustring.gmatch(word2, "[" .. p.letters .. "]")
		while true do
			local c1 = func1(static1, var1)
			local c2 = func2(static2, var2)
			if c1 == nil or c2 == nil then break end
			
			local idx1 = mw.ustring.find(p.letters, c1, 1, true)
			local idx2 = mw.ustring.find(p.letters, c2, 1, true)
			if idx1 and idx2 then
				if idx1 < idx2 then return true end
				if idx1 > idx2 then return false end
			end
		end
	end
	
	return word1 < word2
end

---Abbreviations and text for Han tu references (used by p.createRefTag())
---[[Wiktionary:Beer parlour/2018/December#References for Vietnamese readings listed under Template:vi-readings]]
p.refAbbreviations = {
	tvctdhv = "Trần (1999)";
	hvttd = "Nguyễn (1974)";
	vntd = "Văn Mới (1954)";
	tchvtd = "Thiều Chửu (1942)";
	tdcndg = "Nguyễn (2014)",
	tdcntd = "Nguyễn et al. (2009)",
	gdhn = "Trần (2004)",
	dtdcn = "Vũ (1998)",
	btcn = "Hồ (1976)",
	bonet = "Bonet (1899)",
	genibrel = "Génibrel (1898)",
	taberd = "Taberd & Pigneau de Béhaine (1838)",
}

---Creates a ref tag containing [[Template:vi-ref]].
---Expands abbreviations using p.refAbbreviations.
function p.createRefTag(ref)
	local refFullName = p.refAbbreviations[ref] or ref
	return mw.getCurrentFrame():extensionTag{
		name = "ref",
		args = {
			name = ref,
		},
		content = mw.ustring.format("{{vi-ref|%s.}}", refFullName),
	}
end

---[[Template:vi-readings]]
function p.readings(hanviet, nom, rs, phienthiet, reading)
	local pagename = mw.title.getCurrentTitle().text
	if type(hanviet) == "table" then
		local args = hanviet:getParent().args
		hanviet, nom, rs, phienthiet, reading =
			args.hanviet or args.hv, args.nom or args.n, args.rs or args.sort,
			args.phienthiet or args.phth or args.fanqie, args.reading or args.readings
	end
	
	local lines = {}
	local styles = {
		{
			link = "Hán Việt",
			cat = "Vietnamese Han tu",
			list = hanviet and mw.text.split(hanviet, "%s*,%s*"),
			phienthiet = phienthiet and mw.text.split(phienthiet, "%s*,%s*")
		},
		{
			link = "chữ Nôm|Nôm",
			cat = "Vietnamese Nom",
			list = nom and mw.text.split(nom, "%s*,%s*"),
		},
		{
			link = "Hán Nôm",
			cat = "Vietnamese Han characters with unconfirmed readings",
			list = reading and mw.text.split(reading, "%s*,%s*")
		},
	}
	for i, style in ipairs(styles) do
		if style.list and #style.list > 0 and #style.list[1] > 0 then
			local readings = style.list
--			table.sort(readings, p.comp)
			for j, reading in ipairs(readings) do

				local ref
				local a, b = mw.ustring.match(reading, "(.-)%s*%-%s*(.+)")
				if a then
					reading, ref = a, b
				end

				local spellings = p.allSpellings(reading, true)
				readings[j] = table.concat(spellings, "/")
				
				-- Linking of "切" to "fanqie" for English explanation
				if style.phienthiet and style.phienthiet[j] then
					pruby = "link"
					local ruby = p.ruby(mw.ustring.match(mw.text.trim(style.phienthiet[j]),
						"(%a+) +(.+)"))
					pruby = {}
					if ruby then
						pruby = "nocolor"
						local suffix = p.ruby("切", "thiết")
						pruby = {}
						readings[j] = mw.ustring.format("%s (%s[[fanqie#English|%s]])",
							readings[j], ruby, suffix)
					end
				end

				-- References
				if ref then
					for ref in mw.text.gsplit(ref, "%s*;%s*") do
						readings[j] = readings[j] .. p.createRefTag(ref)
					end
				end
			end
			if #readings > 0 then
				local sortkey = rs or mw.title.getCurrentTitle().text
				readings = table.concat(readings, ", ")
				table.insert(lines, mw.ustring.format("<span class='Hani' lang='vi' style='font-size: 120%%;font-style: normal!important;'>%s</span>: '''[[%s]]''' readings: %s[[Category:%s|%s]] [[Category:Vietnamese lemmas]] [[Category:Vietnamese Han characters]]</br>",
					pagename, style.link, readings, style.cat, sortkey))
			end
		end
	end
	
	return table.concat(lines, "\n")
end

---[[Template:vi-ruby]]
function p.ruby(characters, readings, mark, alts)
	if type(characters) == "table" then
		local args = characters:getParent().args
		characters, readings, mark, alts =
			args[1] or "",
			args[2] or "",
			args.mark or mw.title.getCurrentTitle().text,
			((args.alts and mw.text.split(args.alts, "%s+")) or
				(args.ids and mw.text.split(args.ids, "%s+")) or {})
	end
	
	if not readings then
		return characters
	end
	
	readings = mw.text.split(readings, "[^" .. p.letters .. "]+")
	
	local result = {}
	local character_idx = 1
	local alt_idx = 1
	for character in mw.ustring.gmatch(characters, ".") do
		local is_alt = false
		if character == "*" and alts[alt_idx] then
			character = alts[alt_idx]
			is_alt = true
			alt_idx = alt_idx + 1
		end
		if is_alt or (mw.ustring.match(character, "^%a$") and not character:match("^%w$")) then
			local reading = readings[character_idx]
			if mark and character == mark then
				character = mw.ustring.format("<mark>%s</mark>", character)
				reading = mw.ustring.format("<mark>%s</mark>", reading)
			end
			if pruby == 'link' then
				character = mw.ustring.format(
					"<ruby><rb><span class='Hani'; span style='font-size: 100%%'>[[%s#Vietnamese|%s]]</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 120%%;'>[[%s#Vietnamese|%s]]</span></rt><rp>)</rp></ruby>",
					character, character, reading, reading)
			end
			if pruby == 'nocolor' then
				character = mw.ustring.format(
					"<ruby><rb><span class='Hani' style='color:#000000;'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 120%%;'>%s</span></rt><rp>)</rp></ruby>",
					character, reading)
			end
			if pruby ~= 'link' and pruby ~= 'nocolor' then
				character = mw.ustring.format(
					"<ruby><rb><span class='Hani'>%s</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em;'>%s</span></rt><rp>)</rp></ruby>",
					character, reading)
			end
			character_idx = character_idx + 1
		end
		table.insert(result, character)
	end
	return mw.ustring.format("<span lang='vi' style='font-size: 120%%;font-style: normal!important;'>%s</span>", table.concat(result))
end

function p.hantutab()
	local hantu = mw.ustring.gsub(mw.title.getCurrentTitle().text, '[^一-鿿㐀-䶿﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧-﨩𠀀-𪛟𪜀-𮯯𰀀-𱍏]', '')
	local table_head = '<table class="floatright wikitable" style="text-align:center; font-size:small;"><tr><th colspan="' .. 
		mw.ustring.len(hantu) .. 
		'" style="font-weight:normal;">[[Hán tự]] in this term</th></tr><tr lang="vi" class="Hani" style="font-size:2em; background:white; line-height:1em;">'
	return table_head .. 
		mw.ustring.gsub(hantu, '(.)', '<td style="padding:0.5em;">[[%1#Vietnamese|%1]]</td>') .. 
		'</tr></table>'
end

---Returns the categories indicated by the given wikitext.
function p.classifierCategories(frame)
	local src = frame.args[1]
	local classifiers = {}
	for classifier in mw.ustring.gmatch(mw.ustring.gsub(src, "<[^>]->", ""), "[" .. p.letters .. "]+") do
		if classifier ~= "l" and classifier ~= "vi" and classifier ~= "vi-l" and
				classifier ~= "Vietnamese" then
			local cat = mw.ustring.format("[[Category:Vietnamese nouns classified by %s]]",
				classifier)
			table.insert(classifiers, cat)
		end
	end
	return table.concat(classifiers)
end

function p.new(frame)
	local title = mw.title.getCurrentTitle().subpageText
	local args = frame:getParent().args
	local pos = args[1] or ""
	local def = args[2] or "{{rfdef|vi}}"
	local pos2 = args[3] or (args[4] and "" or false)
	local def2 = args[4] or "{{rfdef|vi}}"
	local pos3 = args[5] or (args[6] and "" or false)
	local def3 = args[6] or "{{rfdef|vi}}"
	local etym = args["e"] or false
	local head = args["head"] or false
	local cat = args["cat"] or false
	local reg = args["reg"] or false
	local cls = args["cls"] or false
	local rdp = args["rdp"] or false
	local nom = args["nom"] or false
	local pic = args["pic"] or false
	local picc = args["picc"] or false
	
	nom = nom and mw.ustring.gsub(nom, "(.)", "[[%1]], ") or false
	nom = nom and mw.ustring.gsub(nom, ", $", "") or false
	if args["h"] then
		etym = "{{vi-etym-sino|" .. args["h"] .. "}}."
	end
	if not etym and mw.ustring.match(title, " ") then
		etym = "{{com|vi"
		for word in mw.text.gsplit(title, " ") do
			etym = etym .. "|" .. word
		end
		etym = etym .. "}}."
	end
	if etym == "-" then etym = false end
	if etym then etym = mw.ustring.gsub(etym, "^%<", "From") end
	
	local result = ""
	
	local function genTitle(text)
		local pos_title = {
			[""] = "Noun", ["n"] = "Noun", ["pn"] = "Proper noun", ["propn"] = "Proper noun", ["pron"] = "Pronoun",
			["v"] = "Verb", ["vf"] = "Verb", ["a"] = "Adjective", ["adj"] = "Adjective", ["adv"] = "Adverb",
			["prep"] = "Preposition", ["postp"] = "Postposition", ["conj"] = "Conjunction",
			["part"] = "Particle", ["suf"] = "Suffix",
			["prov"] = "Proverb", ["id"] = "Idiom", ["ph"] = "Phrase", ["intj"] = "Interjection", ["interj"] = "Interjection",
			["cl"] = "Classifier", ["cls"] = "Classifier", ["num"] = "Numeral", ["abb"] = "Abbreviation", ["deter"] = "Determiner"
		};
		return pos_title[text] or mw.ustring.upper(sub(text, 1, 1)) .. sub(text, 2, -1)
	end
	
	local function genHead(text)
		local pos_head = {
			[""] = "noun", ["n"] = "noun", ["pn"] = "proper noun", ["propn"] = "proper noun", ["v"] = "verb", ["vf"] = "verb form", ["a"] = "adj",
			["postp"] = "post", ["conj"] = "conj", ["part"] = "particle", ["pron"] = "pronoun",
			["prov"] = "proverb", ["id"] = "idiom", ["ph"] = "phrase", ["intj"] = "interj",
			["abb"] = "abbr", ["cl"] = "classifier", ["deter"] = "det"
		};
		return pos_head[text] or text
	end
	
	local function other(class, title, args)
		local code = ""
		if class == "der" and args[class] then
			code = code .. "\n\n===" .. title .. "===\n{{col3|vi|" .. args[class]
			i = 2
			while args[class .. i] do
				code = code .. "|" .. args[class .. i]
				i = i + 1
			end
			code = code .. "}}"
		elseif args[class] then
			code = code .. "\n\n===" .. title .. "===\n* {{l|vi|" .. args[class] .. "}}"
			i = 2
			
			while args[class .. i] do
				code = code .. "\n* {{l|vi|" .. args[class .. i] .. "}}"
				i = i + 1
			end
		end
		return code
	end
	
	result = result .. "==Vietnamese=="
	if args["wp"] then result = result .. "\n{{wikipedia|lang=vi" .. 
		(args["wp"] == "y" and "" or "|" .. args["wp"]) .. "}}" end
	if pic then result = result .. "\n[[File:" .. pic .. "|thumb|" .. 
		(picc or mw.ustring.gsub(title, '^%l', mw.ustring.upper) .. ".") .. "]]" end
	result = result .. other("alt", "Alternative forms", args)
	
	if etym then result = result .. "\n\n===Etymology===\n" .. etym end
	
	result = result .. "\n\n===Pronunciation===\n{{vi-IPA}}"
	result = result .. "\n\n===" .. genTitle(pos) .. "===\n{{vi-" .. genHead(pos) .. (head and ("|head=" .. head) or "") .. 
		((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") .. 
		(((genHead(pos) == "adj" or genHead(pos) == "verb" or genHead(pos) == "adv") and rdp) and "|rdp=" .. rdp or "") .. 
		(nom and "|" .. nom or "") .. 
		"}}\n\n# " .. def
		
	result = result .. other("syn", "=Synonyms=", args)
	result = result .. other("ant", "=Antonyms=", args)
	result = result .. other("der", "=Derived terms=", args)
	result = result .. other("also", "=See also=", args)
	
	if pos2 then
		result = result .. "\n\n===" .. genTitle(pos2) .. "===\n{{vi-" .. genHead(pos2) .. (head and ("|head=" .. head) or "") .. 
		((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") .. 
		(((genHead(pos2) == "adj" or genHead(pos2) == "verb" or genHead(pos2) == "adv") and rdp) and "|rdp=" .. rdp or "") .. 
		(nom and "|" .. nom or "") .. 
		"}}\n\n# " .. def2
	end
	
	if pos3 then
		result = result .. "\n\n===" .. genTitle(pos3) .. "===\n{{vi-" .. genHead(pos3) .. (head and ("|head=" .. head) or "") .. 
		((genHead(pos) == "noun" and cls) and "|cls=" .. cls or "") .. 
		(((genHead(pos3) == "adj" or genHead(pos3) == "verb" or genHead(pos3) == "adv") and rdp) and "|rdp=" .. rdp or "") .. 
		(nom and "|" .. nom or "") .. 
		"}}\n\n# " .. def3
	end
	
	if cat then result = result .. "\n\n{{C|vi|" .. cat .. "}}" end
	
	return result
end

function p.new_der(frame)
	local title = mw.title.getCurrentTitle().subpageText
	local data_module = require("Module:vi/vocab-list")
	local args = frame:getParent().args
	local result = {}
	for _, arg in ipairs(args) do
		table.insert(result, arg)
	end
	
	for _, word in ipairs(data_module) do
		if find(word, title) and word ~= title and not find(word, title .. "[^ ]") and not find(word, "[^ ]" .. title) then
			table.insert(result, word)
		end
	end
	
	local hash, res = {}, {}
	for _, element in ipairs(result) do
		if not hash[element] then
			res[#res + 1] = element
			hash[element] = true
		end
	end
	
	local vi_sort_module = require("Module:vi-sortkey")
	local makeSortKey = require("Module:fun").memoize(vi_sort_module.makeSortKey)
	table.sort(res, function(term1, term2) return makeSortKey(term1) < makeSortKey(term2) end)
	
	return "{{vi-der|" .. table.concat(res, "|") .. "}}"
end

function p.derived(frame)
	local tu_lay_note = "<span style=\"padding-left:4px; padding-right:4px\">&nbsp;</span><span style=\"background:#ffffe0\">(''[[từ láy]]'')</span>"
	local m_columns = require("Module:columns")
	local lang = require("Module:languages").getByCode("vi")
	local m_links = require("Module:links")
	local args = frame:getParent().args
	local pagename = mw.title.getCurrentTitle().text
	local result = {}
	local length = 0
	
	unfold = args["unfold"] and true or false
	title = args["title"] or false
	title_text = title or "Derived terms"

	for i, word in ipairs(args) do
		word, is_tu_lay = mw.ustring.gsub(word, "%:tl", "")
		tu_lay = is_tu_lay > 0 and tu_lay_note or ""
		local word_parts = mw.text.split(mw.ustring.gsub(word, "\n", "" ), ":")
		table.insert(result, m_links.full_link({ 
			lang = lang, 
			term = word_parts[1], 
			gloss = word_parts[2] or nil }) ..
			
		tu_lay)
		
		length = math.max(mw.ustring.len(word), length)
	end
	
	return 
		m_columns.create_table(
			(length > 15 and 2 or 3), 
			result, 
			1, 
			"#F5F5FF",
			((unfold or #result < 7) and false or true), 
			"Derived terms",
			title_text, 
			nil, 
			nil,
			lang
		)
end

return p