Jump to content

Module:Babel

From Wiktionary, the free dictionary


local export = {}

local m_languages = mw.loadData('Module:languages/data/all')
local m_wmf = mw.loadData('Module:wikimedia_languages/data')
local m_scripts = mw.loadData('Module:scripts/data')

local aliases = {
	-- languages
	["en-us"    ] = "en";
	["en-gb"    ] = "en";
	["en-uk"    ] = "en";

	-- scripts
	["IPA"      ] = "Ipach";
	["Polyt"    ] = "Grek";

	-- tech
	["t"        ] = "temp";
	["template" ] = "temp";
}

local tech_boxes = {
	JS = {
		category = "JavaScript coder";
		blurbs = {
			[0] = "This user knows little about JavaScript and just mimics existing usage.";
			"This user knows the basics of how to write JavaScript code and make minor tweaks.";
			"This user has a fair command of JavaScript, and can understand some scripts written by others.";
			"This user can write more complex JavaScript code, and can understand and modify most scripts written by others.";
			"This user can write and understand all kinds of complex JavaScript code.";
			nil;
			"This user is a web browser.";
		}
	};

	Lua = {
		category = "Lua coder";
		blurbs = {
			[0] = "This user knows little about Lua and just mimics existing usage.";
			"This user knows the basics of how to use Lua modules in entries.";
			"This user can use Lua modules with ease, and can write some simple ones.";
			"This user can write more complex Lua modules.";
			"This user can write and understand very complex Lua code.";
			nil;
			"This user is a robot with a built-in Lua implementation.";
		}
	};

	temp = {
		badge = "{{t}}";
		category = "template coder";
		blurbs = {
			[0] = "This user knows little about wiki templates and just mimics existing usage.";
			"This user knows the basics of how to use wiki templates in entries.";
			"This user can use wiki templates with ease, and can write some simple ones.";
			"This user can write more complex wiki templates.";
			"This user can write and understand very complex wiki templates.";
			nil;
			"This user is a MediaWiki installation.";
		}
	};
}

local babel_lang_blurbs = {
	[0] = "This user '''does not understand''' %s (or understands it with considerable difficulty).";
	--  ↑ Lua sucks. Real programming languages count from zero by default.
	"This user is able to contribute with a '''basic''' level of %s.";
	"This user is able to contribute with an '''intermediate''' level of %s.";
	"This user is able to contribute with an '''advanced''' level of %s.";
	"This user speaks %s at a '''near-native''' level.";
	nil; -- level 5, reserved for "professional knowledge"
	"This user is a '''native speaker''' of %s.";
}

local babel_sc_blurbs = {
	[0] = "This user '''cannot read''' %s.";
	"This user has a '''basic understanding''' of '''%s'''.";
	"This user has '''intermediate understanding''' of '''%s'''.";
	"This user has '''advanced understanding''' of '''%s'''.";
	"This user has a '''near-native understanding''' of '''%s'''.";
	nil; -- level 5 is probably never going to be used with scripts, but reserving for the sake of simple code
	"This user's '''native script''' is '''%s'''.";
}

local badge_color = {
	[0] = "#FFB3B3"; "#C0C8FF"; "#77E0E8"; "#99B3FF"; "#CCCC00"; nil; "#6EF7A7"; na = "#CCCCCC";
}

local blurb_color = {
	[0] = "#FFE0E8"; "#F0F8FF"; "#D0F8FF"; "#E0E8FF"; "#FFFF99"; nil; "#C5FCDC"; na = "#EEEEEE";
}

local function make_box(level, badge, blurb)
	-- XXX: get rid of inline styles
	return ([=[
! style="width: 36px; height: 36px; padding: 8px; background:%s; text-align:center;font-size:14pt" |%s
| style="width: 180px; font-size:8pt; padding:4pt; line-height:1.25em; background: %s" |%s
]=]):format(
		badge_color[level], badge,
		blurb_color[level], blurb
	)
end

local function bailout(frame)
	-- ABANDON SHIP
	return frame:expandTemplate { title = "Babel/old"; args = frame:getParent().args }
end

-- XXX: split off into a data module
local script_data = {
	["Arab"] = {
		badge = "ض";
		name = "the Arabic abjad";
	};

	["Armn"] = {
		badge = "Ճ";
		name = "the Armenian alphabet";
	};

	["Beng"] = {
		badge = "ফ";
		name = "the Bengali script";
	};

	["Bopo"] = {
		badge = "ㄅ";
		name = "Zhuyin";
	};

	["Bugi"] = {
		badge = "ᨒ";
		name = "Lontara";
	};

	["Cher"] = {
		badge = "Ꮙ";
		name = "the Cherokee syllabary";
	};

	["Cyrl"] = {
		badge = "Я";
		name = "the Cyrillic alphabet";
	};

	["Cyrs"] = {
		badge = "ѣ";
		name = "the old Cyrillic alphabet";
	};

	["Deva"] = {
		badge = "छ";
		name = "Devanagari";
	};

	["Dsrt"] = {
		badge = "𐐒";
		name = "Deseret alphabet";
	};

	["Egyp"] = {
		badge = "[[File:Egyptian-A.PNG]]";
		name = "Egyptian hieroglyphics";
	};

	["Geor"] = {
		badge = "ლ";
		name = "the Georgian alphabet";
	};

	["Glag"] = {
		badge = "Ⰴ";
		name = "the Glagolitic alphabet";
	};

	["Goth"] = {
		badge = "𐌰";
		name = "the Gothic alphabet";
	};

	["Grek"] = {
		badge = "Ω";
		name = "the Greek alphabet";
	};

	["Gujr"] = {
		badge = "ભ";
		name = "the Gujarati script";
	};

	["Guru"] = {
		badge = "ਝ";
		name = "the Gurmukhi script";
	};

	["Hang"] = {
		badge = "글";
		name = "Hangeul";
	};

	["Hani"] = {
		badge = "漢";
		name = "Hanzi";
	};

	["Hans"] = {
		badge = "简";
		name = "Simplified Chinese";
	};

	["Hant"] = {
		badge = "繁";
		name = "Traditional Chinese";
	};

	["Hebr"] = {
		badge = "ש";
		name = "the Hebrew script";
	};

	["Hira"] = {
		badge = "か";
		name = "Hiragana";
	};

	["IPA"] = {
		badge = "/ʑ/";
		name = "the International Phonetic Alphabet";
	};

	["Java"] = {
		badge = "ꦙ";
		name = "Javanese";
	};

	["Jpan"] = {
		badge = "蓮";
		name = "the Japanese script";
	};

	["Kana"] = {
		badge = "タ";
		name = "Katakana";
	};

	["Khmr"] = {
		badge = "ខ";
		name = "the Khmer script";
	};

	["Knda"] = {
		badge = "ತಃ";
		name = "Kannada";
	};

	["Laoo"] = {
		badge = "ຊ";
		name = "the Lao script";
	};

	["Latn"] = {
		badge = "A";
		name = "the Latin alphabet";
	};

	["Maya"] = {
		badge = "[[File:Ixchel.svg|50px]]";
		name = "Maya hieroglyphics";
	};

	["Mlym"] = {
		badge = "അ";
		name = "Malayalam";
	};

	["Mymr"] = {
		badge = "မ";
		name = "the Burmese script";
	};

	["Ogam"] = {
		badge = "ᚑ";
		name = "the Ogham script";
	};

	["Orya"] = {
		badge = "ଢ";
		name = "the Odia script";
	};

	["Runr"] = {
		badge = "ᚠ";
		name = "the Runic alphabet";
	};

	["Shaw"] = {
		badge = "[[Image:Shavian Hung.svg|20px]]";
		name = "Shavian alphabet";
	};

	["Sinh"] = {
		badge = "ස";
		name = "the Sinhalese script";
	};

	["Sund"] = {
		badge = "ᮚ";
		name = "Sundanese";
	};

	["Syrc"] = {
		badge = "ܐ";
		name = "Syriac";
	};

	["Tale"] = {
		badge = "ᥞ";
		name = "the Tai Le script";
	};

	["Talu"] = {
		badge = "ᦐ";
		name = "the New Tai Lue script";
	};

	["Taml"] = {
		badge = "ஞ";
		name = "Tamil script";
	};

	["Telu"] = {
		badge = "ణ";
		name = "Telugu";
	};

	["Teng"] = {
		badge = "[[Image:Tengwa anga.svg|20px]]";
		name = "Tengwar";
	};

	["Tfng"] = {
		badge = "ⵣ";
		name = "Tifinagh script";
	};

	["Thai"] = {
		badge = "ซ";
		name = "the Thai script";
	};

	["Tibt"] = {
		badge = "ཀ";
		name = "the Tibetan script";
	};

	["Xpeo"] = {
		badge = "𐎠";
		name = "Old Persian cuneiform script";
	};

	["Xsux"] = {
		badge = "𒈠";
		name = "Sumero-Akkadian cuneiform";
	};
}

function export.make_tower(frame)
	local curr_column = {}
	local columns = { curr_column }
	local categories = {}
	local height = 0

	local function add_language_box(lang_code, level)
		local name = m_languages[lang_code][1]
		local wmf_code = m_languages[lang_code].wikimedia_codes and m_languages[lang_code].wikimedia_codes[1] or lang_code
		local lang_native_name = frame:callParserFunction("#language", wmf_code, wmf_code)
		
		table.insert(curr_column, make_box(
			level,
			lang_native_name
				and ('<abbr title="%s">%s</abbr>%s'):format(lang_native_name, lang_code, (level == 6) and "" or ("-" .. level))
				or (lang_code .. ((level == 6) and "" or ("-" .. level))),
			babel_lang_blurbs[level]:format(name)
		))

		if level >= 1 then
			table.insert(categories, "User " .. ((level == 6) and (lang_code .. "-N") or (lang_code .. "-" .. level)))
			table.insert(categories, "User " .. lang_code)
		end
	end

	local function add_script_box(sc_code, level)
		sc_code = sc_code:match("^[a-z]*%-([A-Z][a-z][a-z][a-z])$") or sc_code

		if sc_code == "IPAchar" then -- XXX: hack
			sc_code = "IPA"
		end

		local scinfo = script_data[sc_code] or {}
		local name = scinfo.name or m_scripts[sc_code][1]

		table.insert(curr_column, make_box(
			level, (scinfo.badge and ('<span class="' .. sc_code .. '" style="font-weight:normal;font-size:1.4em;">' .. scinfo.badge .. '</span><br/>') or "") .. ((level == 6) and sc_code or (sc_code .. "-" .. level)),
			babel_sc_blurbs[level]:format(name)
		))

		if level >= 1 then
			table.insert(categories, "User " .. ((level == 6) and (sc_code .. "-N") or (sc_code .. "-" .. level)))
		end
	end

	local function add_tech_box(tech_code, level)
		local tech_info = tech_boxes[tech_code]
		local badge = tech_info.badge or tech_code

		table.insert(curr_column, make_box(
			level, (level == 6) and badge or (badge .. "-" .. level),
			tech_info.blurbs[level]
		))

		if level >= 1 then
			table.insert(categories, "User " .. tech_info.category .. ((level == 6) and "-4" or ("-" .. level)))
		end
	end

	for _, boxspec in ipairs(frame:getParent().args) do
		if boxspec == "!" then
			curr_column = {}
			columns[#columns + 1] = curr_column
		elseif boxspec == "-" then
			table.insert(curr_column, ' | colspan="2" style="height: 36px; padding: 8px;" |\n')
		elseif boxspec == "----" then
			table.insert(curr_column, ' | colspan="2" |<hr />\n') -- XXX
		else
			local lang, level = boxspec:match("^([A-Za-z][A-Za-z%-]-)%-([01234N])$")
			if lang then
				level = tonumber(level) or 6
			else
				lang = boxspec:match("^([A-Za-z][A-Za-z%-]-)$")
				level = 6
			end

			local langname
			if lang then
				if aliases[lang] then
					lang = aliases[lang]
				end

				if m_languages[lang] then
					add_language_box(lang, level, curr_column, categories)
				elseif m_wmf[lang] then
					add_language_box(m_wmf[lang].wiktionary_code, level, curr_column, categories)
				elseif m_scripts[lang] then
					add_script_box(lang, level, curr_column, categories)
				elseif tech_boxes[lang] then
					add_tech_box(lang, level, curr_column, categories)
				else
					mw.log(("Unknown code '%s'"):format(lang))
					return bailout(frame)
				end
			else
				mw.log(("No idea how to interpret '%s'"):format(boxspec))
				return bailout(frame)
			end
		end

		if #curr_column > height then
			height = #curr_column
		end
	end

	if height == 0 then
		height = 1
		table.insert(curr_column, make_box(
			'na', "???",
			"Unknown."
		))
	end

	local output = {}
	local args = frame:getParent().args

	output[#output + 1] = ('{| style="border: 1px solid silver; padding: 2px; float: %s; clear: %s;"\n'):format(args.align or "right", args.align or "right")
	output[#output + 1] = ("|+ '''%s'''\n"):format(args.header or "[[Wiktionary:Babel|Babel]]")
	
	for i = 1, height do
		table.insert(output, " |-\n")
		for _, column in ipairs(columns) do
			if column[i] then
				table.insert(output, column[i])
			else
				table.insert(output, ' | colspan="2" |\n')
			end
		end
	end

	if args.footer then
		output[#output + 1] = ('|-\n | colspan="%u" style="text-align: center;" |%s\n'):format(2 * #columns, args.footer)
	end

	table.insert(output, " |}")

	if mw.title.getCurrentTitle().namespace == mw.site.namespaces.User.id then
		for _, cat in ipairs(categories) do
			table.insert(output, "[[Category:" .. cat .. "]]")
		end
	end

	return table.concat(output)
end

return export