Mô đun:Quốc ngữ

Mô đun rủi ro cao này đang bị khóa không cho sửa đổi để ngăn chặn phá hoại.
Từ điển mở Wiktionary

---Các công cụ để xử lý văn bản quốc ngữ tiếng Việt.
local p = {}

---Biến đổi văn bản theo kiểu dấu truyền thống.
p["đổi dấu cũ"] = function (frame)
    return (p._toTraditionalTones(frame.args[1]))
end
function p._toTraditionalTones(text)
    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

---Biến đổi văn bản theo kiểu dấu hiện đại.
p["đổi dấu mới"] = function (frame)
    return (p._toModernTones(frame.args[1]))
end
function p._toModernTones(text)
    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

---Các dấu thanh kết hợp tiếng Việt trong Unicode.
p.combiningToneMarks = mw.ustring.char(
    0x300,  -- à
    0x301,  -- á
    0x303,  -- ã
    0x309,  -- ả
    0x323   -- ạ
)

---Các dấu phụ kết hợp tiếng Việt trong Unicode.
p.combiningAccentMarks = mw.ustring.char(
    0x302,  -- â
    0x306,  -- ă
    0x308,  -- ü (trung cổ, dành cho [[Bản mẫu:R:VBL]])
    0x31b   -- ơ
)

---Lọc bỏ dấu khỏi văn bản.
p["lọc bỏ dấu"] = function (frame)
    return (p._removeDiacritics(frame.args[1],
        not frame.args.thanh or tonumber(frame.args.thanh) == 1,
        not frame.args["phụ"] or tonumber(frame.args["phụ"]) == 1,
        not frame.args["đ"] or tonumber(frame.args["đ"]) == 1))
end
function p._removeDiacritics(text, toneMarks, accentMarks, stroke)
    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

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

---So sánh hai đơn tiết theo thứ tự sắp xếp từ điển tiếng Việt.
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

---So sánh hai chuỗi theo thứ tự sắp xếp từ điển tiếng Việt.
function p.comp(text1, text2)
    if text1 == text2 then return false end
    
    do
        local func1, static1, var1 = mw.ustring.gmatch(text1, "%a+")
        local func2, static2, var2 = mw.ustring.gmatch(text2, "%a+")
        while true do
            local word1 = func1(static1, var1)
            local word2 = func2(static2, var2)
            if word1 == nil or word2 == nil then break end
            
            if word1 ~= word2 then
                local lower1 = mw.ustring.lower(word1)
                local lower2 = mw.ustring.lower(word2)
                local noTones1 = p._removeDiacritics(lower1, true, false, false)
                local noTones2 = p._removeDiacritics(lower2, true, false, false)
                
                -- So con chữ.
                local oneLess = p.compWord(noTones1, noTones2)
                if oneLess ~= 0 then return oneLess end
                
                -- So con chữ bất kể hoa/thường.
                oneLess = p.compWord(lower1, lower2)
                if oneLess ~= 0 then return oneLess end
                
                -- So thanh điệu.
                oneLess = p.compWord(word1, word2)
                assert(oneLess ~= 0)
                return oneLess
            end
        end
    end
    
    return text1 < text2
end

-- pruby variable for phien thiet hyperlinks (used by p.readings() and p.ruby())
local pruby = {}

---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

---[[Bản mẫu:vie-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 = "Hán tự tiếng Việt",
			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 = "Mục từ chữ Nôm",
			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: 135%%;'>%s</span>: Âm '''[[%s]]''': %s[[Category:%s|%s]] [[Thể loại:Mục từ chữ Nôm]]</br>",
					pagename, style.link, readings, style.cat, sortkey))
			end
		end
	end
	
	return table.concat(lines, "\n")
end

---[[Bản mẫu:vie-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#Tiếng Việt|%s]]</span></rb><rp>(</rp><rt><span style='padding: 0 0.25em; font-size: 135%%;'>[[%s#Tiếng Việt|%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: 125%%;'>%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: 135%%;'>%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;">[[chữ Hán|Chữ Hán]] trong mục từ này</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#Chữ Hán|%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("[[Thể loại:Danh từ tiếng Việt có loại từ %s]]",
				classifier)
			table.insert(classifiers, cat)
		end
	end
	return table.concat(classifiers)
	
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 "Các từ dẫn xuất"

	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), 
			"Các từ dẫn xuất",
			title_text, 
			nil, 
			nil,
			lang
		)
end

return p