<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://massarn.com/w/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%3ALanguages</id>
	<title>Модуль:Languages - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://massarn.com/w/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%3ALanguages"/>
	<link rel="alternate" type="text/html" href="https://massarn.com/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:Languages&amp;action=history"/>
	<updated>2026-10-24T07:46:54Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://massarn.com/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:Languages&amp;diff=2070&amp;oldid=prev</id>
		<title>Buto в 20:05, 12 октября 2026</title>
		<link rel="alternate" type="text/html" href="https://massarn.com/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:Languages&amp;diff=2070&amp;oldid=prev"/>
		<updated>2026-10-12T20:05:20Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Модуль для работы с языками ISO 639&lt;br /&gt;
&lt;br /&gt;
-- загрузка модуля данных с таблицей языков&lt;br /&gt;
-- Module:Languages/data. The expected layout of the record is:&lt;br /&gt;
--   langData[1] → abbreviation (e.g. &amp;#039;англ.&amp;#039;)&lt;br /&gt;
--   langData[2] → article title in Russian (e.g. &amp;#039;Английский язык&amp;#039;)&lt;br /&gt;
--   langData[3] → prepositional form (optional)&lt;br /&gt;
--   langData[4] → genitive form (optional)&lt;br /&gt;
local languages = mw.loadData(&amp;#039;Module:Languages/data&amp;#039;)&lt;br /&gt;
local languagesEn = mw.loadData(&amp;#039;Module:Languages/data-en&amp;#039;)&lt;br /&gt;
local wikidataLanguageCodes = mw.loadData(&amp;#039;Module:Wikidata/Language-codes&amp;#039;)&lt;br /&gt;
local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
local p = {}&lt;br /&gt;
-- forward declaration so helpers above can call it&lt;br /&gt;
local transformLangCase&lt;br /&gt;
&lt;br /&gt;
-- константы&lt;br /&gt;
local CATEGORY_UNKNOWN_LANG =&lt;br /&gt;
	&amp;#039;[[Category:Тептар:Статьи с нераспознанным языком]]&amp;#039;&lt;br /&gt;
local CATEGORY_DUPLICATE_LANG =&lt;br /&gt;
	&amp;#039;[[Category:Тептар:Статьи с дублирующимся языком]]&amp;#039;&lt;br /&gt;
local CATEGORY_UNKNOWN_LANG_REF =&lt;br /&gt;
	&amp;#039;[[Category:Тептар:Статьи с нераспознанным языком (ref)]]&amp;#039;&lt;br /&gt;
local CATEGORY_ALIAS_CODE =&lt;br /&gt;
	&amp;#039;[[Category:Тептар:Статьи с использованием алиасов языковых кодов]]&amp;#039;&lt;br /&gt;
local LOG_NO_LANG_DATA = &amp;#039;Language description for code %s not found&amp;#039;&lt;br /&gt;
local TITLE_PREFIX = &amp;#039;на &amp;#039;&lt;br /&gt;
&lt;br /&gt;
-- Returns true when the string is either nil or an empty string.&lt;br /&gt;
-- This helper is used to guard early-exit branches and avoid&lt;br /&gt;
-- calling mw.ustring functions on invalid values.&lt;br /&gt;
local function isEmpty(s)&lt;br /&gt;
	return s == nil or s == &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Generates HTML error message for unknown language codes or Wikidata IDs.&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   type - &amp;#039;lang&amp;#039; for language codes, &amp;#039;wikidata&amp;#039; for Wikidata IDs&lt;br /&gt;
--   code - the unknown code/ID to display in error&lt;br /&gt;
local function generateError(type, code)&lt;br /&gt;
	if type == &amp;#039;wikidata&amp;#039; then&lt;br /&gt;
		return &amp;#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Неизвестный Wikidata ID: &amp;#039; .. mw.text.nowiki(code) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Неизвестный языковой код: &amp;#039;&lt;br /&gt;
			.. mw.text.nowiki(code)&lt;br /&gt;
			.. &amp;#039;. Обратитесь на [[Обсуждение модуля:Languages|специальную страницу]] для добавления данного кода.&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Builds a wiki link from a language record coming from&lt;br /&gt;
-- Returns string like &amp;#039;[[Английский язык|англ.]]&amp;#039;.&lt;br /&gt;
local function buildLanguageLink(langData)&lt;br /&gt;
	if not langData then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;[[&amp;#039; .. langData[2] .. &amp;#039;|&amp;#039; .. langData[1] .. &amp;#039;]]&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Builds a HTML span used as an inline language reference.&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   text        — abbreviation to show inside brackets.&lt;br /&gt;
--   title       — tooltip text (full wording in the target case).&lt;br /&gt;
--   variant     — &amp;#039;square&amp;#039; to use [ ... ], otherwise round ( ... ).&lt;br /&gt;
--   includeNbsp — when false no leading NBSP is added; otherwise NBSP.&lt;br /&gt;
-- Returns a string similar to {{refinfo|англ.|на английском языке}}&lt;br /&gt;
local function buildRefSpan(text, title, variant, includeNbsp)&lt;br /&gt;
	local template = mw.getCurrentFrame():expandTemplate{&lt;br /&gt;
        title = &amp;#039;refinfo&amp;#039;,&lt;br /&gt;
        args = {&lt;br /&gt;
			text,&lt;br /&gt;
			TITLE_PREFIX .. mw.text.encode(title or &amp;#039;&amp;#039;),&lt;br /&gt;
			(variant == &amp;#039;square&amp;#039;) and &amp;#039;в&amp;#039; or (variant == &amp;#039;none&amp;#039;) and &amp;#039;н&amp;#039; or &amp;#039;&amp;#039;&lt;br /&gt;
		}&lt;br /&gt;
    }&lt;br /&gt;
	return (includeNbsp == false) and template:gsub(&amp;quot;&amp;amp;nbsp;&amp;quot;, &amp;quot;&amp;quot;, 1) or template&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- A thin wrapper around Module:Arguments.getArgs with the&lt;br /&gt;
-- options we use consistently across entry points:&lt;br /&gt;
--   trim = true           — trims whitespace&lt;br /&gt;
--   removeBlanks = false  — preserves explicit empty parameters&lt;br /&gt;
local function getInvokeArgs(frame)&lt;br /&gt;
	return getArgs(frame, { trim = true, removeBlanks = false, frameOnly = true })&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Looks up a language record by code in Module:Languages/data.&lt;br /&gt;
-- Normalizes case to lowercase. Returns two values:&lt;br /&gt;
--   1) record table or nil when code is unknown&lt;br /&gt;
--   2) normalized code (lowercase)&lt;br /&gt;
local function getLanguageData(code)&lt;br /&gt;
	if isEmpty(code) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
    local normalized_code = mw.ustring.lower(code)&lt;br /&gt;
	local record = languages[normalized_code]&lt;br /&gt;
	if not record then -- take &amp;quot;parent&amp;quot; language name, if normalized_code is a language variant&lt;br /&gt;
		record = languages[normalized_code:match(&amp;quot;^[^-]+&amp;quot;)] &lt;br /&gt;
	end&lt;br /&gt;
	return record, normalized_code&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns tracking category for alias code usage.&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   code - the language code to check&lt;br /&gt;
-- Returns:&lt;br /&gt;
--   category string or empty string&lt;br /&gt;
local function getCodeCategory(code)&lt;br /&gt;
	if isEmpty(code) then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local normalized = mw.ustring.lower(code)&lt;br /&gt;
	if languages.aliases and languages.aliases[normalized] then&lt;br /&gt;
		return CATEGORY_ALIAS_CODE&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Resolves language record and normalized code with unified error handling.&lt;br /&gt;
-- Returns:&lt;br /&gt;
--   l, normalized                 when code exists in data&lt;br /&gt;
--   nil, nil, errorOrEmptyString  when code is empty/unknown (&amp;#039;&amp;#039; or error html)&lt;br /&gt;
local function resolveLanguage(code, showError)&lt;br /&gt;
	if isEmpty(code) then&lt;br /&gt;
		return nil, nil, &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local l, normalized = getLanguageData(code)&lt;br /&gt;
	if l then&lt;br /&gt;
		return l, normalized&lt;br /&gt;
	end&lt;br /&gt;
	return nil, nil, (showError and generateError(&amp;#039;lang&amp;#039;, code) or &amp;#039;&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Given a language code, returns:&lt;br /&gt;
--   • rendered link to the language article using its abbreviation, and&lt;br /&gt;
--   • normalized code to be used in the &amp;#039;lang&amp;#039; attribute.&lt;br /&gt;
-- If the code is unknown but non-empty, returns the raw code and empty lang.&lt;br /&gt;
-- If the input is empty, returns two empty strings.&lt;br /&gt;
local function buildLanguageLinkForCode(code)&lt;br /&gt;
	local l, normalized_code = resolveLanguage(code, false)&lt;br /&gt;
    if l then&lt;br /&gt;
		return buildLanguageLink(l), (normalized_code or &amp;#039;&amp;#039;)&lt;br /&gt;
	elseif not isEmpty(code) then&lt;br /&gt;
		return code, &amp;#039;&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;#039;&amp;#039;, &amp;#039;&amp;#039;&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Renders a ref span for a known ISO 639 code. Returns nil when code&lt;br /&gt;
-- is unknown so caller can decide on a fallback strategy.&lt;br /&gt;
local function buildRefForCode(code, variant, includeNbsp, mode)&lt;br /&gt;
	local l, normalized = resolveLanguage(code, false)&lt;br /&gt;
	if not l then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local text = (mode == &amp;#039;iso&amp;#039;) and normalized or l[1]&lt;br /&gt;
&lt;br /&gt;
	return buildRefSpan(&lt;br /&gt;
		text,&lt;br /&gt;
		transformLangCase(normalized or code, &amp;#039;prepositional&amp;#039;),&lt;br /&gt;
		variant,&lt;br /&gt;
		includeNbsp&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Fallback renderer for unknown codes via Template:ref-&amp;lt;code&amp;gt;, with&lt;br /&gt;
-- categorization. Uses &amp;#039;und&amp;#039; when a specific template doesn&amp;#039;t exist.&lt;br /&gt;
local function renderUnknownRef(code, showError, refVariant, includeNbsp)&lt;br /&gt;
	if showError then&lt;br /&gt;
		return generateError(&amp;#039;lang&amp;#039;, code)&lt;br /&gt;
	end&lt;br /&gt;
	return buildRefSpan(&amp;#039;неопр.&amp;#039;, &amp;#039;неопределённом языке&amp;#039;, refVariant, includeNbsp) .. CATEGORY_UNKNOWN_LANG_REF:gsub(&amp;#039;\\]\\]&amp;#039;, &amp;#039;|&amp;#039; .. code .. &amp;#039;]]&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Internal implementation of the language-name case transformation.&lt;br /&gt;
-- Computes either prepositional (&amp;#039;на английском языке&amp;#039;) or&lt;br /&gt;
-- genitive (&amp;#039;английского языка&amp;#039;) forms. If specific forms are&lt;br /&gt;
-- provided in Module:Languages/data via l[3]/l[4], they win.&lt;br /&gt;
-- Otherwise, applies a set of heuristics to generate the forms.&lt;br /&gt;
local function _transformLangCaseImpl(code, case)&lt;br /&gt;
	-- Resolve the language record; unknown code gets a readable placeholder&lt;br /&gt;
	local l = getLanguageData(code)&lt;br /&gt;
	if not l then&lt;br /&gt;
		return &amp;#039;&amp;amp;lt;неизвестный код &amp;#039; .. code .. &amp;#039;&amp;amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Prefer explicit forms from data when present:&lt;br /&gt;
	--   l[3] = prepositional, l[4] = genitive&lt;br /&gt;
	if case == &amp;#039;prepositional&amp;#039; and l[3] then&lt;br /&gt;
		return l[3]&lt;br /&gt;
	end&lt;br /&gt;
	if case == &amp;#039;genitive&amp;#039; and l[4] then&lt;br /&gt;
		return l[4]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Derive a base noun phrase:&lt;br /&gt;
	-- 1) take explicit Russian title if present (l[2]),&lt;br /&gt;
	--    otherwise fetch the language name via mw.language&lt;br /&gt;
	-- 2) lowercase everything for stable pattern processing&lt;br /&gt;
	-- 3) strip the word &amp;quot;язык&amp;quot; and optional parenthetical &amp;quot;(язык)&amp;quot;&lt;br /&gt;
	local ln = mw.ustring&lt;br /&gt;
		.lower(l[2] or mw.language.fetchLanguageName(code, &amp;#039;ru&amp;#039;))&lt;br /&gt;
		:gsub(&amp;#039;%s+язык%s+&amp;#039;, &amp;#039; &amp;#039;)&lt;br /&gt;
		:gsub(&amp;#039;%s*%(?язык%)?%s*&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
	if not ln then&lt;br /&gt;
		-- Final fallback string when even a base name is unavailable&lt;br /&gt;
		local fallback = (&lt;br /&gt;
			case == &amp;#039;prepositional&amp;#039; and (&amp;#039;языке с ISO-кодом &amp;#039; .. code .. &amp;#039; (?)&amp;#039;)&lt;br /&gt;
			or (&amp;#039;языка с ISO-кодом &amp;#039; .. code .. &amp;#039; (?)&amp;#039;)&lt;br /&gt;
		)&lt;br /&gt;
		return fallback&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Special-case: names ending with &amp;quot;лингва&amp;quot; (e.g., &amp;quot;линга франка&amp;quot;)&lt;br /&gt;
	-- only need a final vowel change: а → е/ы depending on target case&lt;br /&gt;
	if ln:match(&amp;#039;.*лингва$&amp;#039;) then&lt;br /&gt;
		local r = ln:gsub(&amp;#039;а$&amp;#039;, (case == &amp;#039;prepositional&amp;#039; and &amp;#039;е&amp;#039; or &amp;#039;ы&amp;#039;))&lt;br /&gt;
		return r&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Adjectival language names (&amp;quot;...ский&amp;quot;, &amp;quot;...цкий&amp;quot;, &amp;quot;...ный&amp;quot;),&lt;br /&gt;
	-- optionally followed by a parenthetical qualifier, require&lt;br /&gt;
	-- morphological agreement. The rules below implement common&lt;br /&gt;
	-- Russian inflection patterns:&lt;br /&gt;
	--   - &amp;quot;нЫЙ/нИЙ&amp;quot; → &amp;quot;нОМ/нЕМ&amp;quot; (prep.) or &amp;quot;нОГО/нЕГО&amp;quot; (gen.)&lt;br /&gt;
	--   - &amp;quot;СКИЙ/ЦКИЙ&amp;quot; → &amp;quot;СКОМ/ЦКОМ&amp;quot; (prep.) or &amp;quot;СКОГО/ЦКОГО&amp;quot; (gen.)&lt;br /&gt;
	if&lt;br /&gt;
		mw.ustring.match(ln, &amp;#039;[сц]кий$&amp;#039;)&lt;br /&gt;
		or ln:match(&amp;#039;ный$&amp;#039;)&lt;br /&gt;
		or mw.ustring.match(ln, &amp;#039;[сц]кий%s%b()$&amp;#039;)&lt;br /&gt;
		or ln:match(&amp;#039;ный%s%b()$&amp;#039;)&lt;br /&gt;
	then&lt;br /&gt;
		ln = mw.ustring&lt;br /&gt;
			.gsub(&lt;br /&gt;
				mw.ustring&lt;br /&gt;
					.gsub(ln, &amp;#039;н([ыи])й(%A)&amp;#039;, function(y, s)&lt;br /&gt;
						-- &amp;quot;нЫЙ/нИЙ&amp;quot; endings: pick target case and keep following separator&lt;br /&gt;
						return (&lt;br /&gt;
							case == &amp;#039;prepositional&amp;#039; and (y == &amp;#039;ы&amp;#039; and &amp;#039;ном&amp;#039; or &amp;#039;нем&amp;#039;)&lt;br /&gt;
							or (y == &amp;#039;ы&amp;#039; and &amp;#039;ного&amp;#039; or &amp;#039;него&amp;#039;)&lt;br /&gt;
						) .. s&lt;br /&gt;
					end)&lt;br /&gt;
					:gsub(&amp;#039;ный$&amp;#039;, (case == &amp;#039;prepositional&amp;#039; and &amp;#039;ном&amp;#039; or &amp;#039;ного&amp;#039;)),&lt;br /&gt;
				&amp;#039;([сц]к)ий(%A)&amp;#039;,&lt;br /&gt;
				(case == &amp;#039;prepositional&amp;#039; and &amp;#039;%1ом%2&amp;#039; or &amp;#039;%1ого%2&amp;#039;)&lt;br /&gt;
			)&lt;br /&gt;
			:gsub(&amp;#039;ский$&amp;#039;, (case == &amp;#039;prepositional&amp;#039; and &amp;#039;ском&amp;#039; or &amp;#039;ского&amp;#039;))&lt;br /&gt;
			:gsub(&amp;#039;цкий$&amp;#039;, (case == &amp;#039;prepositional&amp;#039; and &amp;#039;цком&amp;#039; or &amp;#039;цкого&amp;#039;))&lt;br /&gt;
&lt;br /&gt;
		-- If the name ends with a qualifier in parentheses and the case ending&lt;br /&gt;
		-- did not land immediately before the closing paren, append&lt;br /&gt;
		-- &amp;quot;языке/языка&amp;quot; before the qualifier to keep a natural phrasing.&lt;br /&gt;
		local hasClosingParen = ln:match(&amp;#039;%)$&amp;#039;) ~= nil&lt;br /&gt;
		local endsWithCase1 = ln:match(case == &amp;#039;prepositional&amp;#039; and &amp;#039;ом%)$&amp;#039; or &amp;#039;ого%)$&amp;#039;) ~= nil&lt;br /&gt;
		local endsWithCase2 = ln:match(case == &amp;#039;prepositional&amp;#039; and &amp;#039;нем%)$&amp;#039; or &amp;#039;него%)$&amp;#039;)&lt;br /&gt;
			~= nil&lt;br /&gt;
		if hasClosingParen and not (endsWithCase1 or endsWithCase2) then&lt;br /&gt;
			local r, s = ln:gsub(&lt;br /&gt;
				&amp;#039;(%s)(%b())$&amp;#039;,&lt;br /&gt;
				(case == &amp;#039;prepositional&amp;#039; and &amp;#039;%1языке%1%2&amp;#039; or &amp;#039;%1языка%1%2&amp;#039;)&lt;br /&gt;
			)&lt;br /&gt;
			if s == 1 then&lt;br /&gt;
				return r&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		-- Default phrasing for adjectival names&lt;br /&gt;
		local result = (case == &amp;#039;prepositional&amp;#039; and (ln .. &amp;#039; языке&amp;#039;) or (ln .. &amp;#039; языка&amp;#039;))&lt;br /&gt;
		return result&lt;br /&gt;
	else&lt;br /&gt;
		-- Non‑adjectival names (base nouns): prepend &amp;quot;языке/языка&amp;quot;&lt;br /&gt;
		local result = (case == &amp;#039;prepositional&amp;#039; and (&amp;#039;языке &amp;#039; .. ln) or (&amp;#039;языка &amp;#039; .. ln))&lt;br /&gt;
		return result&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Public wrapper kept for backwards compatibility with existing&lt;br /&gt;
-- callers in this module and other modules. Do not move above&lt;br /&gt;
-- function definitions to avoid upvalue shadowing.&lt;br /&gt;
function transformLangCase(code, case)&lt;br /&gt;
	return _transformLangCaseImpl(code, case)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- export for other modules that `require(&amp;quot;Module:Languages&amp;quot;).transformLangCase`&lt;br /&gt;
p.transformLangCase = transformLangCase&lt;br /&gt;
&lt;br /&gt;
-- P U B L I C   E N T R Y   P O I N T S&lt;br /&gt;
-- Entry point: builds a ref span by Wikidata item id coming from #invoke.&lt;br /&gt;
-- Delegates to p.getWikidataRefHtml after parsing the argument.&lt;br /&gt;
function p.getWikidataRefHtmlFrame(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
	return p.getWikidataRefHtml(args[1] or &amp;#039;&amp;#039;, showError)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Builds a ref span from a Wikidata item id of a language.&lt;br /&gt;
-- Uses a preloaded mapping Module:Wikidata/Language-codes to&lt;br /&gt;
-- resolve item → ISO 639 code, then renders the standard ref span.&lt;br /&gt;
function p.getWikidataRefHtml(wikidataItemId, showError)&lt;br /&gt;
	local code = wikidataLanguageCodes[wikidataItemId]&lt;br /&gt;
	if code == nil then&lt;br /&gt;
		if showError then&lt;br /&gt;
			return generateError(&amp;#039;wikidata&amp;#039;, wikidataItemId)&lt;br /&gt;
		end&lt;br /&gt;
		mw.log(&amp;#039;Language code not found for &amp;#039; .. wikidataItemId)&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local rendered = buildRefForCode(code, nil, false, &amp;#039;&amp;#039;)&lt;br /&gt;
	if not rendered then&lt;br /&gt;
		if showError then&lt;br /&gt;
			return generateError(&amp;#039;lang&amp;#039;, code)&lt;br /&gt;
		end&lt;br /&gt;
		mw.log(string.format(LOG_NO_LANG_DATA, tostring(code)))&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	-- Добавляем категорию если код является алиасом&lt;br /&gt;
	return rendered .. getCodeCategory(code)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Entry point: returns a language abbreviation by ISO 639 code.&lt;br /&gt;
-- Unknown/empty codes produce an empty string.&lt;br /&gt;
function p.abbr(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local code = args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
	local l, _normalized, err = resolveLanguage(code, showError)&lt;br /&gt;
	if l then&lt;br /&gt;
		return l[1] .. getCodeCategory(code)&lt;br /&gt;
	end&lt;br /&gt;
	return err or &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Entry point: returns the Russian article title (full language name)&lt;br /&gt;
-- by ISO 639 code. Unknown/empty codes produce an empty string.&lt;br /&gt;
-- When output=en, returns English language name from data_en.&lt;br /&gt;
function p.name(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local code = args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	local mode = args[&amp;#039;mode&amp;#039;] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
&lt;br /&gt;
	if not isEmpty(code) then&lt;br /&gt;
		if mode == &amp;#039;en&amp;#039; then&lt;br /&gt;
			local _, normalized = getLanguageData(code)&lt;br /&gt;
			local l = normalized and languagesEn[normalized] or nil&lt;br /&gt;
			if l then&lt;br /&gt;
				return l[1] .. getCodeCategory(code)&lt;br /&gt;
			elseif showError then&lt;br /&gt;
				return generateError(&amp;#039;lang&amp;#039;, code)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			local l = getLanguageData(code)&lt;br /&gt;
			if l then&lt;br /&gt;
				return l[2] .. getCodeCategory(code)&lt;br /&gt;
			elseif showError then&lt;br /&gt;
				return generateError(&amp;#039;lang&amp;#039;, code)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- TODO: Вынести в отдельный модуль, так как логика сложная не для этого модуля, тут не только работа с языками&lt;br /&gt;
--&lt;br /&gt;
-- Entry point: builds a comma-separated list of pairs&lt;br /&gt;
-- (language link + supplied text). The input is a flat sequence:&lt;br /&gt;
--   code1 | text1 | code2 | text2 | ...&lt;br /&gt;
-- If text for the last code is missing, only the language link is emitted.&lt;br /&gt;
-- Unknown codes are marked with a category and wrapped in a span.&lt;br /&gt;
function p.list(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	    local curr_lang = nil&lt;br /&gt;
	local noItalic = args[&amp;#039;noItalic&amp;#039;]&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	local categories = {}&lt;br /&gt;
	local langs_seen = {}&lt;br /&gt;
&lt;br /&gt;
	-- Итерируемся по позиционным аргументам по порядку&lt;br /&gt;
	local maxIndex = 0&lt;br /&gt;
	for k, _ in pairs(args) do&lt;br /&gt;
		if type(k) == &amp;#039;number&amp;#039; and k &amp;gt; maxIndex then&lt;br /&gt;
			maxIndex = k&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- Use ipairs for sequential iteration, but handle gaps by checking maxIndex&lt;br /&gt;
	for i = 1, maxIndex do&lt;br /&gt;
		local v = args[i]&lt;br /&gt;
		local value = v or &amp;#039;&amp;#039;&lt;br /&gt;
		if curr_lang == nil then&lt;br /&gt;
			if value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				curr_lang = value&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			if value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				local link, lang_code = buildLanguageLinkForCode(curr_lang)&lt;br /&gt;
				local category = getCodeCategory(curr_lang)&lt;br /&gt;
				if category ~= &amp;#039;&amp;#039; then&lt;br /&gt;
					categories[category] = true&lt;br /&gt;
				end&lt;br /&gt;
				if langs_seen[lang_code] ~= nil then&lt;br /&gt;
					categories[CATEGORY_DUPLICATE_LANG] = true&lt;br /&gt;
				else&lt;br /&gt;
					langs_seen[lang_code] = true&lt;br /&gt;
				end&lt;br /&gt;
			local list_item&lt;br /&gt;
			if lang_code ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				    --- Temporary fix for [[Шаблон:L6e]] (see [[Служебная:Постоянная ссылка/151687926#Опять наинжинерили]])&lt;br /&gt;
					local italic = noItalic == nil and not (languages.no_italics and languages.no_italics[lang_code]) or false &lt;br /&gt;
					local style = italic and &amp;quot;style=&amp;#039;font-style:italic&amp;#039;&amp;quot; or &amp;#039;&amp;#039;&lt;br /&gt;
					list_item = link&lt;br /&gt;
						.. &amp;quot;&amp;amp;nbsp;&amp;lt;span dir=&amp;#039;auto&amp;#039;&amp;quot; .. style .. &amp;quot;lang=&amp;#039;&amp;quot;&lt;br /&gt;
						.. lang_code&lt;br /&gt;
						.. &amp;quot;&amp;#039;&amp;gt;&amp;quot;&lt;br /&gt;
						.. value&lt;br /&gt;
						.. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
				else&lt;br /&gt;
					list_item = link&lt;br /&gt;
						.. &amp;quot; &amp;lt;span class=&amp;#039;unknown-foreign-lang&amp;#039;&amp;gt;&amp;quot;&lt;br /&gt;
						.. value&lt;br /&gt;
						.. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
						.. CATEGORY_UNKNOWN_LANG&lt;br /&gt;
				end&lt;br /&gt;
				table.insert(parts, list_item)&lt;br /&gt;
			else&lt;br /&gt;
				local link, _ = buildLanguageLinkForCode(curr_lang)&lt;br /&gt;
				local category = getCodeCategory(curr_lang)&lt;br /&gt;
				if category ~= &amp;#039;&amp;#039; then&lt;br /&gt;
					categories[category] = true&lt;br /&gt;
				end&lt;br /&gt;
				table.insert(parts, link)&lt;br /&gt;
			end&lt;br /&gt;
		curr_lang = nil&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    if curr_lang ~= nil then&lt;br /&gt;
		local link, _ = buildLanguageLinkForCode(curr_lang)&lt;br /&gt;
		local category = getCodeCategory(curr_lang)&lt;br /&gt;
		if category ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			categories[category] = true&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(parts, link)&lt;br /&gt;
	end&lt;br /&gt;
	if #parts == 0 then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local result = table.concat(parts, &amp;#039;, &amp;#039;)&lt;br /&gt;
	for cat, _ in pairs(categories) do&lt;br /&gt;
		result = result .. cat&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Entry point: builds a sequence of inline language references&lt;br /&gt;
-- for the provided ISO 639 codes. Positional args are codes.&lt;br /&gt;
-- When parameter &amp;#039;в&amp;#039; is present, square brackets are used.&lt;br /&gt;
-- For unknown codes tries Template:ref-&amp;lt;code&amp;gt;, otherwise uses &amp;#039;und&amp;#039;.&lt;br /&gt;
function p.list_ref(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local brackets = args[&amp;#039;brackets&amp;#039;] or args[&amp;#039;в&amp;#039;]&lt;br /&gt;
	local mode = args[&amp;#039;mode&amp;#039;] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
	local includeNbsp = args[&amp;#039;includeNbsp&amp;#039;] ~= &amp;#039;false&amp;#039; and args[&amp;#039;includeNbsp&amp;#039;] ~= false&lt;br /&gt;
	local refVariant&lt;br /&gt;
	if brackets == &amp;#039;none&amp;#039; then&lt;br /&gt;
		refVariant = &amp;#039;none&amp;#039;&lt;br /&gt;
	elseif brackets == nil or brackets == &amp;#039;&amp;#039; or brackets == &amp;#039;()&amp;#039; then&lt;br /&gt;
		refVariant = nil -- round&lt;br /&gt;
	elseif brackets == &amp;#039;[]&amp;#039; or brackets == &amp;#039;в&amp;#039; or brackets == &amp;#039;square&amp;#039; or brackets == &amp;#039;1&amp;#039; or brackets == true then&lt;br /&gt;
		refVariant = &amp;#039;square&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		refVariant = nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- We rely strictly on named params for brackets/mode; only numeric args are language codes.&lt;br /&gt;
	-- But we need to filter out positional args that were used as options&lt;br /&gt;
&lt;br /&gt;
	local chunks = {}&lt;br /&gt;
	local join = not isEmpty(args[&amp;#039;join&amp;#039;])&lt;br /&gt;
	local joinTexts, joinTitles = {}, {}&lt;br /&gt;
	local langs_seen = {}&lt;br /&gt;
	local categories = {}&lt;br /&gt;
&lt;br /&gt;
	-- Process positional arguments as language codes&lt;br /&gt;
	-- Use ipairs to iterate through args, but skip known named parameters&lt;br /&gt;
	for idx, code in ipairs(args) do&lt;br /&gt;
		-- Skip if this is a known named parameter&lt;br /&gt;
		local isNamedParam = false&lt;br /&gt;
		if code == brackets or code == tostring(brackets) then&lt;br /&gt;
			isNamedParam = true&lt;br /&gt;
		elseif code == mode then&lt;br /&gt;
			isNamedParam = true&lt;br /&gt;
		elseif code == &amp;#039;join&amp;#039; or code == &amp;#039;error&amp;#039; or code == &amp;#039;class&amp;#039; then&lt;br /&gt;
			isNamedParam = true&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		if not isNamedParam and code and not isEmpty(code) then&lt;br /&gt;
			local normalized = mw.ustring.lower(code)&lt;br /&gt;
			local category = getCodeCategory(normalized)&lt;br /&gt;
			if category ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				categories[category] = true&lt;br /&gt;
			end&lt;br /&gt;
			if langs_seen[normalized] ~= nil then&lt;br /&gt;
				categories[CATEGORY_DUPLICATE_LANG] = true&lt;br /&gt;
			else&lt;br /&gt;
				langs_seen[normalized] = true&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			if join then&lt;br /&gt;
				local l = getLanguageData(normalized)&lt;br /&gt;
				if l then&lt;br /&gt;
					local text = mode == &amp;#039;iso&amp;#039; and normalized or l[1]&lt;br /&gt;
					table.insert(joinTexts, text)&lt;br /&gt;
					table.insert(joinTitles, transformLangCase(normalized, &amp;#039;prepositional&amp;#039;))&lt;br /&gt;
				else&lt;br /&gt;
					table.insert(chunks, renderUnknownRef(normalized, showError, refVariant, includeNbsp))&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				local rendered = buildRefForCode(normalized, refVariant, includeNbsp, mode)&lt;br /&gt;
				table.insert(chunks, rendered or renderUnknownRef(normalized, showError, refVariant, includeNbsp))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
    if join and #joinTexts &amp;gt; 0 then&lt;br /&gt;
		local text = table.concat(joinTexts, &amp;#039;, &amp;#039;)&lt;br /&gt;
		local title = table.concat(joinTitles, &amp;#039;, &amp;#039;)&lt;br /&gt;
		table.insert(chunks, buildRefSpan(text, title, refVariant, includeNbsp))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local result = table.concat(chunks)&lt;br /&gt;
	for cat, _ in pairs(categories) do&lt;br /&gt;
		result = result .. cat&lt;br /&gt;
	end&lt;br /&gt;
    return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- args:&lt;br /&gt;
--   1           — language code&lt;br /&gt;
--   case|form   — &amp;#039;l2&amp;#039;|&amp;#039;l3&amp;#039;|&amp;#039;l4&amp;#039; or &amp;#039;nom&amp;#039;|&amp;#039;gen&amp;#039;|&amp;#039;prep&amp;#039; or &amp;#039;р&amp;#039;|&amp;#039;п&amp;#039; (default &amp;#039;l2&amp;#039;)&lt;br /&gt;
--                  &amp;#039;р&amp;#039; → genitive, &amp;#039;п&amp;#039; → prepositional&lt;br /&gt;
--   mode        — &amp;#039;en&amp;#039; or &amp;#039;iso&amp;#039; to override language output&lt;br /&gt;
--   error       — when truthy, returns error html for unknown code&lt;br /&gt;
function p.transform(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local code = args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	-- Treat empty strings as absent to ensure proper fallback to &amp;#039;l2&amp;#039;&lt;br /&gt;
	local form = args[&amp;#039;case&amp;#039;]&lt;br /&gt;
	if isEmpty(form) then&lt;br /&gt;
		form = args[&amp;#039;form&amp;#039;]&lt;br /&gt;
	end&lt;br /&gt;
	if isEmpty(form) then&lt;br /&gt;
		form = &amp;#039;l2&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local mode = args[&amp;#039;mode&amp;#039;] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
&lt;br /&gt;
	if isEmpty(code) then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local l, normalized = getLanguageData(code)&lt;br /&gt;
	local normCode = normalized or &amp;#039;&amp;#039;&lt;br /&gt;
	local category = getCodeCategory(code)&lt;br /&gt;
&lt;br /&gt;
	-- Output overrides&lt;br /&gt;
	if mode == &amp;#039;iso&amp;#039; then&lt;br /&gt;
		return normCode .. category&lt;br /&gt;
	elseif mode == &amp;#039;en&amp;#039; then&lt;br /&gt;
		local e = languagesEn[normCode]&lt;br /&gt;
		if e then&lt;br /&gt;
			return e[1] .. category&lt;br /&gt;
		end&lt;br /&gt;
		return showError and generateError(&amp;#039;lang&amp;#039;, code) or &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Russian forms&lt;br /&gt;
	if not l then&lt;br /&gt;
		return showError and generateError(&amp;#039;lang&amp;#039;, code) or &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local f = mw.ustring.lower(form)&lt;br /&gt;
	if f == &amp;#039;l2&amp;#039; or f == &amp;#039;nom&amp;#039; or f == &amp;#039;nominative&amp;#039; then&lt;br /&gt;
		return (l[2] and mw.ustring.lower(l[2]) or &amp;#039;&amp;#039;) .. category&lt;br /&gt;
	elseif f == &amp;#039;l3&amp;#039; or f == &amp;#039;gen&amp;#039; or f == &amp;#039;genitive&amp;#039; or f == &amp;#039;р&amp;#039; then&lt;br /&gt;
		return transformLangCase(normCode, &amp;#039;genitive&amp;#039;) .. category&lt;br /&gt;
	elseif f == &amp;#039;l4&amp;#039; or f == &amp;#039;prep&amp;#039; or f == &amp;#039;prepositional&amp;#039; or f == &amp;#039;п&amp;#039; then&lt;br /&gt;
		return transformLangCase(normCode, &amp;#039;prepositional&amp;#039;) .. category&lt;br /&gt;
	else&lt;br /&gt;
		-- default to nominative (lowercase)&lt;br /&gt;
		return (l[2] and mw.ustring.lower(l[2]) or &amp;#039;&amp;#039;) .. category&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Entry point: returns the prepositional form for a language code.&lt;br /&gt;
function p.transform_lang(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local code = args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
	local l, normalized, err = resolveLanguage(code, showError)&lt;br /&gt;
	if l then&lt;br /&gt;
		return transformLangCase(normalized or code, &amp;#039;prepositional&amp;#039;) .. getCodeCategory(code)&lt;br /&gt;
	end&lt;br /&gt;
	return err or &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Entry point: returns the genitive form for a language code.&lt;br /&gt;
function p.transform_lang_genitive(frame)&lt;br /&gt;
	local args = getInvokeArgs(frame)&lt;br /&gt;
	local code = args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	local showError = args[&amp;#039;error&amp;#039;] and true or false&lt;br /&gt;
	local l, normalized, err = resolveLanguage(code, showError)&lt;br /&gt;
	if l then&lt;br /&gt;
		return transformLangCase(normalized or code, &amp;#039;genitive&amp;#039;) .. getCodeCategory(code)&lt;br /&gt;
	end&lt;br /&gt;
	return err or &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Buto</name></author>
	</entry>
</feed>