From Omniversalis

Documentation for this module may be created at Module:Language/text/doc

-- This module is a replacement for {{lang}} and all lang-x templates.
-- It wraps text in an HTML tag containing a lang attribute with a specific
-- language code. This often makes no visible changes to the text, but can help
-- web browsers choose the right font, screen readers use the right
-- pronunciation and more. The plain function wraps the text in the HTML tag,
-- but does not otherwise change the output. The named function adds the name of
-- the language before the text.

-- Load required modules.
local mLanguageName = require("Module:Language/name")
local yesno = require("Module:Yesno")
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local data = mw.loadData("Module:Language/data/wp languages")

-- Lazily initialise [[Module:Arguments]], as we will only need it sometimes.
-- Not loading it when we don't have to will keep its transclusion count down,
-- which helps to reduce load on the job queue.
local mArguments

-- The p table contains functions that will be available from #invoke and that
-- will be available to other Lua modules (including for use in the test cases).
-- The f table contains functions linking #invoke functions to Lua functions.
local p, f = {}, {}

function f.plain(code, text, options)
	checkType("plain", 1, code, "string")
	checkType("plain", 2, text, "string")
	checkType("plain", 3, options, "table", true)
	options = options or {}
	local name = p._fetchLanguageName(code)
	if not name then
		return nil
	return p._createElement(code, text, name, options)

function f.named(code, text, options)
	checkType("named", 1, code, "string")
	checkType("named", 2, text, "string")
	checkType("named", 3, options, "table", true)
	options = options or {}
	local name = p._fetchLanguageName(code)
	if not name then
		return nil
	return string.format(
		"[[%s language|%s]]: %s",
		p._createElement(code, text, name, options)

function p._fetchLanguageName(code)
	-- Fetches a language name, given a language code. If no name can be
	-- found, returns nil.
	if not code then
		return nil
	local name = mLanguageName.fuzzy{code = code}
	if name and name ~= "" then
		return name
	return nil

function p._createElement(code, text, name, options)
	-- Creates the HTML element.
	-- Check whether a preferred code is specified in the Wikipedia language
	-- data for the input code we are given.
	code = data[code] and data[code][2]	or code
	local tag = options.tagName or "span"
	local root = mw.html.create(tag)
		:attr("lang", code)
		:wikitext(text .. p._categorise(code, name, options))
	return tostring(root)

function p._categorise(code, name, options)
	-- Generates the tracking category.

	local function makeCategory(cat)
		-- Makes a category wikilink.
		return string.format("[[%s:%s]]",[14].name, cat)

	local function makeTitle(...)
		-- Get a title object, using pcall to call to
		-- avoid producing script errors. will result
		-- in a script error if we are over the expensive function count
		-- limit, among other fun and exciting scenarios.
		local success, title = pcall(, ...)
		if success then
			return title
			return nil

	-- Don't categorise if nocat is set.
	if yesno(options.nocat, true) then
		return ""

	-- Don't categorise if we are not on a content page.
	-- Allow specification of so that this function can be
	-- tested as if it were being run on different pages. This option
	-- isn't provided for Lua functions as it would probably not be used
	-- and would decrease performance slightly.
	local titleObj =
		and makeTitle(
		or mw.title.getCurrentTitle()
	if not titleObj or not titleObj.isContentPage then
		return ""

	-- Assemble the category.
	if code == "en" or code == "eng" then
		return makeCategory(
			"Articles containing explicitly cited English-language text"
		local categoryName = "Articles containing "
			.. name
			.. "-language text"
		local categoryTitle = makeTitle(categoryName, 14)
		if categoryTitle and categoryTitle.exists then
			return makeCategory(categoryName)
			return makeCategory(
				"Articles containing non-English-language text"

-- Make the #invoke functions. The function names are taken from the f table.
-- The #invoke function is named p.funcName, and the function it calls is named
-- f.funcName. If the result of f.funcName(args) is nil, then p.funcName
-- returns the blank string. This allows for use of both Lua-like and
-- wikitext-like idioms should any of the validation checks fail. We use
-- [[Module:Arguments]] to get the arguments from the frame object. We also
-- make the f.funcName functions available to other Lua modules under the name
-- p._funcName.
for funcName, func in pairs(f) do
	p[funcName] = function (frame)
		mArguments = require("Module:Arguments")
		local args = mArguments.getArgs(frame)
		-- Get the code and text variables.
		local code = args.code
		local text = args.text
		if not code or not text then
			-- Give up gracefully if we don't have the required input.
			return text or ""
		-- Pass values through to the options table.
		local options = {}
		options.tagName = args.type
		options.nocat = args.nocat
		return f[funcName](code, text, options) or ""
	-- Create the function to access from other Lua modules.
	p["_" .. funcName] = func

return p