Module:Lang: Difference between revisions
meta>Trappist the monk more; |
meta>Trappist the monk lang() & lang_xx() have same special variant subtag test; |
||
Line 126: | Line 126: | ||
return nil, nil, nil, nil; | return nil, nil, nil, nil; | ||
end | end | ||
if source:match ('^%a%a%a?%-%a%a%a%a%-%a%a%-%d%d%d%d+$') then -- ll-Ssss-RR-variant (where variant is 4 digits) | if source:match ('^%a%a%a?%-%a%a%a%a%-%a%a%-%d%d%d%d+$') then -- ll-Ssss-RR-variant (where variant is 4 digits) | ||
code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$'); | code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$'); | ||
Line 184: | Line 184: | ||
end | end | ||
if is_set (script) then | if is_set (script) then | ||
script = script:lower(); -- ensure that we use and return lower case version of this | |||
if not lang_name_table.script[script] then | if not lang_name_table.script[script] then | ||
return code, nil, nil, nil; -- language code ok, invalid script, don't know about the others (don't care?) | return code, nil, nil, nil; -- language code ok, invalid script, don't know about the others (don't care?) | ||
Line 193: | Line 193: | ||
if is_set (region) then | if is_set (region) then | ||
if not lang_name_table.region[region | script = region:lower(); -- ensure that we use and return lower case version of this | ||
if not lang_name_table.region[region] then | |||
return code, script, nil, nil; | return code, script, nil, nil; | ||
end | end | ||
end | end | ||
if is_set (variant) then | if is_set (variant) then | ||
variant = variant:lower(); -- ensure that we use and return lower case version of this | |||
if not lang_name_table.variant[variant] then | if not lang_name_table.variant[variant] then | ||
return code, script, region, nil; | return code, script, region, nil; | ||
end | end -- does this duplicate/replace tests in lang() and lang_xx()? | ||
if not in_array (code, lang_name_table.variant[variant]['prefixes']) and not in_array (table.concat ({code, '-', script}), lang_name_table.variant[variant]['prefixes']) then | if not in_array (code, lang_name_table.variant[variant]['prefixes']) and not in_array (table.concat ({code, '-', script}), lang_name_table.variant[variant]['prefixes']) then | ||
return code, script, region, nil; | return code, script, region, nil; | ||
Line 479: | Line 479: | ||
code, subtags.script, subtags.region, subtags.variant = get_ietf_parts (args.code); | code, subtags.script, subtags.region, subtags.variant = get_ietf_parts (args.code); | ||
if not (code and subtags.script and subtags.region and subtags.variant) then | if not (code and subtags.script and subtags.region and subtags.variant) then | ||
return make_error_msg (table.concat ({'{{lang}}: unknown language code: ', args.code or 'missing'}), args.nocat); | return make_error_msg (table.concat ({'{{lang}}: unknown language code: ', args.code or 'missing'}), args.nocat); | ||
Line 638: | Line 638: | ||
end | end | ||
if is_set (subtags.variant) then | if is_set (subtags.variant) then -- special case test for |variant= | ||
if not in_array (code, lang_name_table.variant[subtags.variant]['prefixes']) then | if is_set (subtags.script) then | ||
return make_error_msg (table.concat ({'{{lang | if not in_array (table.concat ({code, '-', subtags.script}), lang_name_table.variant[subtags.variant]['prefixes']) then | ||
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.script, '-', subtags.variant}), args.nocat); | |||
end | |||
else | |||
if not in_array (code, lang_name_table.variant[subtags.variant]['prefixes']) then | |||
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.variant}), args.nocat); | |||
end | |||
end | end | ||
end | end |
Revision as of 19:49, 19 November 2017
Language templates |
---|
Languages (ISO 639) |
|
Wiktionary links |
|
Other |
|
Data |
This Lua module is used on approximately 1,160,000 pages, or roughly 17046% of all pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
This module depends on the following other modules: |
This module exists primarily to provide correct html markup for non-English language text where that text is used in the English Wikipedia. It has a secondary purpose of providing correct visual rendering for this non-English text. The module was developed to consolidate processing for {{Lang}}
, the {{lang-??}}
(most), and {{Transl}}
templates into a single source and to use a clearly defined data set extracted from international standards. It provides error checking and reporting to ensure that the html rendered is correct for browsers and screen readers.
Other templates that get language name support from this module are:
{{Native name}}
Data set
The data set is specified in Module:Language/name/data and its included data modules:
- language tag-and-name data
- Module:Language/data/iana languages – from IANA language-subtag-registry file
- Module:Language/data/ISO 639-3 – from sil.org UTF-8 Complete Code Tables Set
- Module:Language/data/wp languages – sourcing for the data in this module is unknown
- language script data
- Module:Language/data/iana scripts – from IANA language-subtag-registry file
- language region data
- Module:Language/data/iana regions – from IANA language-subtag-registry file
- language variant data
- Module:Language/data/iana variants – from IANA language-subtag-registry file
- suppressed-script data
- Module:Language/data/iana suppressed scripts – from IANA language-subtag-registry file
The data set also includes supplementary data modules:
- override and other non-standard data
- Module:Lang/data – For example, when IANA disagrees with ISO 639-3 or when the standard language name is cumbersome or contains information not suitable for use in article space, the
override
table can hold that language information - Module:Lang/ISO 639 synonyms – maps three character ISO 639-2, -2T, -3 codes to two character ISO 639-1 codes – from Codes for the Representation of Names of Languages
- Module:Lang/name to tag – reversed language tag-and-name data so that the language name is the key and the language tag is the value
- Module:Lang/data – For example, when IANA disagrees with ISO 639-3 or when the standard language name is cumbersome or contains information not suitable for use in article space, the
Error messages and categorization
Mainspace articles that have errors are placed in appropriate error categories:
Maintenance categories:
See also
MoS on foreign words:
--[=[
Lua support for the {{lang}} and {{lang-xx}} templates and replacement of various supporting templates.
]=]
require('Module:No globals');
local p = {};
local getArgs = require ('Module:Arguments').getArgs;
local lang_name_table = mw.loadData ('Module:Language/name/data');
local lang_data = mw.loadData ('Module:Lang/data'); -- language name override and transliteration tool-tip tables
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.
]]
local function is_set( var )
return not (var == nil or var == '');
end
--[[--------------------------< T O _ B O O L E A N >----------------------------------------------------------
Returns true for 'yes', false for 'no', and nil for any other value.
]]
local function to_boolean (param)
if param == 'yes' then
return true
elseif param == 'no' then
return false
else
return nil
end
end
--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------
Whether needle is in haystack
]]
local function in_array( needle, haystack )
if needle == nil then
return false;
end
for n,v in ipairs( haystack ) do
if v == needle then
return n;
end
end
return false;
end
--[[--------------------------< F O R M A T _ I E T F _ T A G >------------------------------------------------
prettify ietf tags to use recommended subtag formats:
code: lower case
script: sentence case
region: upper case
variant: lower case
]]
local function format_ietf_tag (code, script, region, variant)
local out = {};
local c;
table.insert (out, code:lower());
if is_set (script) then
c = script:match ('^%a'):upper(); -- make script sentence case
script = script:lower():gsub ('^%a', c, 1);
table.insert (out, script);
end
if is_set (region) then
table.insert (out, region:upper());
end
if is_set (variant) then
table.insert (out, variant:lower());
end
return table.concat (out, '-');
end
--[[--------------------------< G E T _ I E T F _ P A R T S >--------------------------------------------------
extracts and returns IETF language tag parts:
primary language subtag (required) - 2 or 3 character IANA language code
script subtag - four character IANA script code
region subtag - two-letter or three digit IANA region code
variant subtag - four digit or 5-8 alnum variant code
in any one of these forms
lang lang-variant
lang-script lang-script-variant
lang-region lang-region-variant
lang-script-region lang-script-region-variant
each of lang, script, region, and variant, when used, must be valid
returns four values. Valid parts are returned as themselves; omitted parts are returned as empty strings, invalid
parts are returned as nil.
see http://www.rfc-editor.org/rfc/bcp/bcp47.txt section 2.1
]]
local function get_ietf_parts (source)
local code;
local script = '';
local region = '';
local variant = '';
local c;
if not is_set (source) then
return nil, nil, nil, nil;
end
if source:match ('^%a%a%a?%-%a%a%a%a%-%a%a%-%d%d%d%d+$') then -- ll-Ssss-RR-variant (where variant is 4 digits)
code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%d%d%d%-%d%d%d%d+$') then -- ll-Ssss-DDD-variant (where region is 3 digits; variant is 4 digits)
code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%a%a%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-Ssss-RR-variant (where variant is 5-8 alnum characters)
code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%d%d%d%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-Ssss-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)
code, script, region, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%d%d%d%d+$') then -- ll-Ssss-variant (where variant is 4 digits)
code, script, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-Ssss-variant (where variant is 5-8 alnum characters)
code, script, variant = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%a%a%-%d%d%d%d+$') then -- ll-RR-variant (where variant is 4 digits)
code, region, variant = source:match ('^(%a%a%a?)%-(%a%a)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-%d%d%d%-%d%d%d%d+$') then -- ll-DDD-variant (where region is 3 digits; variant is 4 digits)
code, region, variant = source:match ('^(%a%a%a?)%-(%d%d%d)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-%a%a%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-RR-variant (where variant is 5-8 alnum characters)
code, region, variant = source:match ('^(%a%a%a?)%-(%a%a)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%d%d%d%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-DDD-variant (where region is 3 digits; variant is 4 digits)
code, region, variant = source:match ('^(%a%a%a?)%-(%d%d%d)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%d%d%d%d+$') then -- ll-variant (where variant is 4 digits)
code, variant = source:match ('^(%a%a%a?)%-(%d%d%d%d)$');
elseif source:match ('^%a%a%a?%-[%a%d][%a%d][%a%d][%a%d][%a%d]+$') then -- ll-variant (where variant is 5-8 alnum characters)
code, variant = source:match ('^(%a%a%a?)%-([%a%d][%a%d][%a%d][%a%d][%a%d][%a%d]?[%a%d]?[%a%d]?)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%a%a$') then -- ll-Ssss-RR
code, script, region = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a%-%d%d%d$') then -- ll-Ssss-DDD (region is 3 digits)
code, script, region = source:match ('^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)$');
elseif source:match ('^%a%a%a?%-%a%a%a%a$') then -- ll-Ssss
code, script = source:match ('^(%a%a%a?)%-(%a%a%a%a)$');
elseif source:match ('^%a%a%a?%-%a%a$') then -- ll-RR
code, region = source:match ('^(%a%a%a?)%-(%a%a)$');
elseif source:match ('^%a%a%a?%-%d%d%d$') then -- ll-DDD (region is 3 digits)
code, region = source:match ('^(%a%a%a?)%-(%d%d%d)$');
elseif source:match ('^%a%a%a?$') then -- ll
code = source:match ('^(%a%a%a?)$');
elseif source:match ('^1%a+$') then -- special case for two Linguist list identifiers in Module:Lang/data override table
code = source:match ('^(1%a%a)$'); -- these may need tweaks in future if other alphanumeric Linguist list identifiers are added
else
return nil, nil, nil, nil; -- don't know what we got but it is malformed
end
code = code:lower(); -- ensure that we use and return lower case version of this
if not (lang_data.override[code] or lang_name_table.lang[code]) then
return nil, nil, nil, nil; -- invalid language code, don't know about the others (don't care?)
end
if is_set (script) then
script = script:lower(); -- ensure that we use and return lower case version of this
if not lang_name_table.script[script] then
return code, nil, nil, nil; -- language code ok, invalid script, don't know about the others (don't care?)
end
end
if is_set (region) then
script = region:lower(); -- ensure that we use and return lower case version of this
if not lang_name_table.region[region] then
return code, script, nil, nil;
end
end
if is_set (variant) then
variant = variant:lower(); -- ensure that we use and return lower case version of this
if not lang_name_table.variant[variant] then
return code, script, region, nil;
end -- does this duplicate/replace tests in lang() and lang_xx()?
if not in_array (code, lang_name_table.variant[variant]['prefixes']) and not in_array (table.concat ({code, '-', script}), lang_name_table.variant[variant]['prefixes']) then
return code, script, region, nil;
end
end
return code, script, region, variant; -- return the good bits
end
--[=[-------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
]=]
local function make_error_msg (msg, nocat)
local out = {};
table.insert (out, '<span style="font-size:100%" class="error">error: ');
table.insert (out, msg);
table.insert (out, ' ([[:Category:lang and lang-xx template errors|help]])')
table.insert (out, '</span>');
if (0 == namespace) and not is_set (nocat) then -- only categorize in article space
table.insert (out, '[[Category:lang and lang-xx template errors]]');
end
return table.concat (out);
end
--[=[-------------------------< M A K E _ W I K I L I N K >----------------------------------------------------
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only
link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an
empty string.
]=]
local function make_wikilink (link, display)
if is_set (link) then
if is_set (display) then
return table.concat ({'[[', link, '|', display, ']]'});
else
return table.concat ({'[[', link, ']]'});
end
else
return '';
end
end
--[[--------------------------< M A K E _ T E X T _ S P A N >--------------------------------------------------
]]
local function make_text_span (code, text, rtl, italic, size)
local span = {};
table.insert (span, '<span lang="'); -- open <span> tag
table.insert (span, code); -- language attribute
table.insert (span, '"');
if rtl then
table.insert (span, ' dir="rtl"'); -- for right to left languages
end
if is_set (size) then -- {{lang}} only
table.insert (span, table.concat ({' style="font-size:', size, ';"'}))
end
table.insert (span, '>'); -- close the opening span tag
if italic then
table.insert (span, table.concat ({"''", text, "''"})); -- text with italic markup
else
table.insert (span, text); -- DEFAULT: text is not italicized
end
table.insert (span, '</span>'); -- close the span
if rtl then
table.insert (span, '‎'); -- make sure the browser knows that we're at the end of the rtl
end
return table.concat (span); -- put it all together and done
end
--[[--------------------------< M A K E _ C A T E G O R Y >----------------------------------------------------
]]
local function make_category (code, language_name, nocat)
local cat = {};
if (0 ~= namespace) or nocat then -- only categorize in article space
return ''; -- return empty string for concatenation
end
table.insert (cat, '[[Category:Articles containing ');
if ('en' == code) or ('eng' == code) then
table.insert (cat, 'explicitly cited English');
elseif 'art' == code then
table.insert (cat, 'constructed')
else
table.insert (cat, language_name);
end
table.insert (cat, '-language text]]');
return table.concat (cat);
end
--[[--------------------------< M A K E _ T R A N S L I T >----------------------------------------------------
return translit <span>...</span> else return empty string
The value |script= is not used in {{transl}} for this purpose; instead it uses |code. Because language scripts
are listed in the {{transl}} switches they are included in the data tables. The script parameter is introduced
at {{Language with name and transliteration}}. If |script= is set, this function uses it in preference to code.
To avoid confusion, in this module and the templates that use it, the transliteration script parameter is renamed
to be |translit-script= (in this function, tscript)
]]
local function make_translit (code, language_name, translit, std, tscript)
local title;
local tout = {};
local title_table = lang_data.translit_title_table; -- table of transliteration standards and the language codes and scripts that apply to those standards
table.insert (tout, "''<span lang=\"");
table.insert (tout, code);
table.insert (tout, "-Latn\" title=\"");
if not is_set (std) and not is_set (tscript) then -- when neither standard nor script specified
table.insert (tout, language_name); -- write a generic tool tip
table.insert (tout, ' transliteration');
elseif is_set (std) and is_set (tscript) then -- when both are specified
if title_table[std][tscript] then -- and legitimate
table.insert (tout, title_table[std][tscript]); -- add the appropriate text to the tool tip
else
return ''; -- one or both invalid, set up for an error message
end
elseif is_set (std) then -- translit-script not set, use language code
if not title_table[std] then return ''; end -- invalid standard, setupt for error message
if title_table[std][code] then
table.insert (tout, title_table[std][code]);
else -- code doesn't match
table.insert (tout, title_table[std]['default']); -- so use the standard's default
end
else -- here if translit-script set but translit-std not set
if title_table['NO_STD'][tscript] then
table.insert (tout, title_table['NO_STD'][tscript]); -- use translit-script if set
elseif title_table['NO_STD'][code] then
table.insert (tout, title_table['NO_STD'][code]); -- use language code
else
table.insert (tout, language_name); -- write a generic tool tip
table.insert (tout, ' transliteration');
end
end
table.insert (tout, '">');
table.insert (tout, translit);
table.insert (tout, "</span>''");
return table.concat (tout);
end
--[[--------------------------< V A L I D A T E _ T E X T >---------------------------------------------------
This function checks the content of args.text and returns empty string if nothing is amiss else it returns an
error message. The tests are for empty or missing text and for improper or disallowed use of apostrophe markup.
Italic rendering is controlled by the |italic= template parameter so italic markup should never appear in args.text
either as ''itself''' or as '''''bold italic'''''.
Also protects single leading and trailing single quote marks from being converted to bold by the addition of
adjacent italic markup.
]]
local function validate_text (template, args)
if not is_set (args.text) then
return make_error_msg (table.concat ({'{{', template, '}}: no text'}), args.nocat);
end
if 'lang-xx' == template then -- for the time being, this error checking does not apply to {{lang}}
if args.text:find ("\'\'\'\'\'[\']+") then -- because we're looking, look for 6+ appostrophes
return make_error_msg (table.concat ({'{{', template, '}}: text has malformed markup'}), args.nocat);
end
if args.text:match ("%f[\']\'\'[^\']+\'\'%f[^\']") or args.text:match ("\'\'\'\'\'[^\']+\'\'\'\'\'") then -- italic but not bold, or bold italic
return make_error_msg (table.concat ({'{{', template, '}}: text has italic markup'}), args.nocat);
end
if args.text:find ("\'\'\'\'") then -- because we're looking, look for 4 apostrophes
return make_error_msg (table.concat ({'{{', template, '}}: text has malformed markup'}), args.nocat);
end
if args.italic then -- protect single quote marks from being converted to bold markup
args.text = args.text:gsub ("^\'[^\']+", "<span></span>%1"); -- leading single quote mark
args.text = args.text:gsub ("[^\']+\'$", "%1<span></span>"); -- trailing single quote mark
end
end
end
--[[--------------------------< S U B T A G _ C H E C K >------------------------------------------------------
checks the subtags: script, region, and variant to be valid and in agreement with any tags that are included in
the main language code: if |script=Cyrl and language code is 'abq-Cyrl' the two script must agree (case insensitive)
returns the selected subtag and nil error message;
returns empty string and nil error message when both language code subtag and matching subtag parameter are not set
returns nil and error message else
]]
local function subtag_check (name, args_code, code_subtag, args_subtag, nocat)
if not is_set (code_subtag) and not is_set (args_subtag) then -- no subtags, then bale
return ''; -- empty string for concatenation
end
args_subtag = args_subtag and args_subtag:lower(); -- so we only need do this once; prettify later
if not is_set (code_subtag) then -- if no ietf subtag in args.code
if is_set (args_subtag) then -- and if |<name>= has a value
if lang_name_table[name][args_subtag] then -- and that value is legitimate subtag
code_subtag = args_subtag; -- then use |<name>=
else
return nil, make_error_msg (table.concat ({'{{lang-xx}}: invalid ' .. name .. ': ', args_subtag}), nocat);
end
end
else -- here when language code has a subtag
if is_set (args_subtag) and (code_subtag ~= args_subtag) then -- if there is a subtag parameter then it must match
return nil, make_error_msg (table.concat ({'{{lang-xx}}: code / ' .. name .. ' mismatch: ', args_code:lower(), ' / ', args_subtag}), nocat);
end
end
return code_subtag;
end
--[[--------------------------< L A N G >----------------------------------------------------------------------
<includeonly>{{#invoke:lang|lang|code={{{1|}}}|text={{{2|}}}|rtl={{{rtl|}}}|italic={{{italic|}}}|size={{{size|}}}|nocat={{{nocat|}}}}}</includeonly>
|code = the BCP47 language code
|text = the displayed text in language specified by code
|rtl = boolean true identifies the language specified by code as a right-to-left language
|size = css keyword appropriate for use with css font-size:<size>
|nocat = boolean true inhibits normal categorization; error categories are not affected
]]
function p.lang (frame)
local args = getArgs(frame);
if args[1] and args.code then
return make_error_msg ('{{lang}}: conflicting: {{{1}}} and |code=', args.nocat);
else
args.code = args[1] or args.code;
end
if args[2] and args.text then
return make_error_msg ('{{lang}}: conflicting: {{{2}}} and |text=', args.nocat);
else
args.text = args[2] or args.text;
end
args.rtl = args.rtl == 'yes'; -- convert to boolean: 'yes' -> true, other values -> false
args.italic = to_boolean(args.italic); -- convert to boolean or nil: 'yes' -> true, 'no' -> false; else nil
local out = {};
local language_name;
local subtags = {};
local code;
code, subtags.script, subtags.region, subtags.variant = get_ietf_parts (args.code);
if not (code and subtags.script and subtags.region and subtags.variant) then
return make_error_msg (table.concat ({'{{lang}}: unknown language code: ', args.code or 'missing'}), args.nocat);
end
local msg = validate_text ('lang', args); -- ensure that |text= is set (italic test disabled for the time being)
if is_set (msg) then
return msg;
end
if is_set (subtags.script) then -- if script set override rtl setting
if in_array (subtags.script, lang_data.rtl_scripts) then
args.rtl = true; -- script is an rtl script
else
args.rtl = false; -- script is not an rtl script
end
end
if is_set (subtags.variant) then -- special case test for |variant=
if is_set (subtags.script) then
if not in_array (table.concat ({code, '-', subtags.script}), lang_name_table.variant[subtags.variant]['prefixes']) then
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.script, '-', subtags.variant}), args.nocat);
end
else
if not in_array (code, lang_name_table.variant[subtags.variant]['prefixes']) then
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.variant}), args.nocat);
end
end
end
if not args.italic then -- args.italic controls
if 'latn' == subtags.script then -- script set to latn
args.italic = true; -- DEFAULT for {{lang}} templates is upright; but if latn script
else
args.italic = false; -- italic not set; script not latn
end
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant); -- format to recommended subtag styles
if lang_data.override[code] then
language_name = lang_data.override[code][1]
elseif lang_name_table.lang[code] then
language_name = lang_name_table.lang[code][1]; -- table entries sometimes have multiple names, always take the first one
end
table.insert (out, make_text_span (args.code, args.text, args.rtl, args.italic, args.size));
table.insert (out, make_category (args.code, language_name, args.nocat));
return table.concat (out); -- put it all together and done
end
--[[--------------------------< L A N G _ X X >----------------------------------------------------------------
<includeonly>{{#invoke:lang|lang_xx
|code=<code>
|script={{{script|}}}
|region={{{region|}}}
|variant={{{variant|}}}
|text={{{1|}}}
|link={{{links|{{{link}}}}}}
|rtl={{{rtl|}}}
|nocat={{{nocat|}}}
|italic={{{italic|}}}
|translation={{{lit|}}}
|translit={{{translit|}}}
|translit-script={{{translit-script|}}}
|translit-std={{{translit-std|}}}}}</includeonly>
|code = (required) the BCP47 language code
|script = BCP47 script name; especially for use with languages that use multiple writing systems; yields to the script subtag in |code= if present [not yet implemented]
|text = (required) the displayed text in language specified by code
|link = boolean true (default) links language specified by code to associated language article
|rtl = boolean true identifies the language specified by code as a right-to-left language
|nocat = boolean true inhibits normal categorization; error categories are not affected
|italic = boolean true (default) renders displayed text in italic font; when |italic= not set and |script= set to something other than Latn then args.italic='no' [not yet implemented]
|lit = text that is a literal translation of text
for those {{lang-xx}} templates that support transliteration:
|translit = text that is a transliteration of text
|translit-std = the standard that applies to the transliteration
|translit-script = ISO 15924 script name; falls back to code
For {{lang-xx}}, the positional parameters are:
{{{1}}} text
{{{2}}} transliterated text
{{{3}}} literal translation text
]]
function p.lang_xx (frame)
local args = getArgs(frame, {parentFirst= true}); -- parameters in the template override parameters set in the {{#invoke:}}; is that the right thing to do?
if args[1] and args.text then
return make_error_msg ('{{lang-xx}}: conflicting: {{{1}}} and |text=', args.nocat);
else
args.text = args[1] or args.text;
end
if args[2] and args.translit then
return make_error_msg ('{{lang-xx}}: conflicting: {{{2}}} and |translit=', args.nocat);
else
args.translit = args[2] or args.translit
end
if args[3] and (args.translation or args.lit) then
return make_error_msg ('{{lang-xx}}: conflicting: {{{3}}} and |lit= or |translation=', args.nocat);
elseif args.translation and args.lit then
return make_error_msg ('{{lang-xx}}: conflicting: |lit= and |translation=', args.nocat);
else
args.translation = args[3] or args.translation or args.lit;
end
if args.links and args.link then
return make_error_msg ('{{lang-xx}}: conflicting: |links= and |link=', args.nocat);
else
args.link = args.link or args.links;
end
args.size = nil; -- size not supported in {{lang-xx}}
args.rtl = args.rtl == 'yes'; -- convert to boolean: 'yes' -> true, other values -> false
args.italic = to_boolean(args.italic); -- convert to boolean or nil: 'yes' -> true, 'no' -> false; else nil
local out = {};
local language_name;
local subtags = {};
local code;
local translit_script;
local translit;
local translit_title;
code, subtags.script, subtags.region, subtags.variant = get_ietf_parts (args.code);
if not (code and subtags.script and subtags.region and subtags.variant) then
return make_error_msg (table.concat ({'{{lang-xx}}: unknown language code: ', args.code or 'missing'}), args.nocat);
end
local msg = validate_text ('lang-xx', args); -- ensure that |text= is set, does not contain italic markup and is protected from improper bolding
if is_set (msg) then
return msg;
end
for name, value in pairs (subtags) do -- spin through the subtags table and consolidate code and parameter-provided language subtags
subtags[name], msg = subtag_check (name, args.code, value, args[name], args.nocat);
if not subtags[name] then
return msg; -- some sort of error detected, return the error message
end
end
if is_set (subtags.script) then -- if script set override rtl setting
if in_array (subtags.script, lang_data.rtl_scripts) then
args.rtl = true; -- script is an rtl script
else
args.rtl = false; -- script is not an rtl script
end
end
if is_set (subtags.variant) then -- special case test for |variant=
if is_set (subtags.script) then
if not in_array (table.concat ({code, '-', subtags.script}), lang_name_table.variant[subtags.variant]['prefixes']) then
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.script, '-', subtags.variant}), args.nocat);
end
else
if not in_array (code, lang_name_table.variant[subtags.variant]['prefixes']) then
return make_error_msg (table.concat ({'{{lang}}: invalid code-variant combination: ', code, '-', subtags.variant}), args.nocat);
end
end
end
if args.italic == nil then -- args.italic controls
if not is_set (subtags.script) or ('latn' == subtags.script) then -- script not set then default; script set to latn same
args.italic = true; -- DEFAULT for {{lang-xx}} templates is to italicize
else
args.italic = false; -- italic not set; script not latn
end
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant); -- format to recommended subtag styles
if lang_data.override[code] then
language_name = lang_data.override[code][1]
elseif lang_name_table.lang[code] then
language_name = lang_name_table.lang[code][1]; -- table entries sometimes have multiple names, always take the first one
end
translit_script = args['translit-script'] or language_name; -- for translit prefer |trans-script= over language
if 'no' == args.link then
table.insert (out, language_name); -- language name without wikilink
else
table.insert (out, make_wikilink (language_name .. ' language', language_name)); -- language name with wikilink
end
table.insert (out, ': '); -- separator
table.insert (out, make_text_span (args.code, args.text, args.rtl, args.italic, args.size))
if is_set (args.translit) then -- transliteration (not supported in {{lang}}); not supported in all {{lang-xx}}
table.insert (out, ', <small>');
translit_title = mw.title.makeTitle (0, 'Romanization of ' .. language_name)
if translit_title.exists and ('no' ~= args.link) then
table.insert (out, make_wikilink ('Romanization of ' .. translit_script or language_name, 'translit.'));
else
table.insert (out, '<abbr title="transliteration">translit.</abbr>');
end
table.insert (out, ' </small>');
translit = make_translit (args.code, language_name, args.translit, args['translit-std'], args['translit-script'])
if is_set (translit) then
table.insert (out, translit);
else
return make_error_msg (table.concat ({'{{lang-xx}}: invalid translit-std: \'', args['translit-std'] or 'missing', '\' or transli-script: \'', args['translit-script'] or 'missing', '\''}), args.nocat);
end
end
if is_set (args.translation) then -- translation (not supported in {{lang}})
table.insert (out, ', <small>');
if 'no' == args.link then
table.insert (out, '<abbr title="literal translation">lit.</abbr>');
else
table.insert (out, make_wikilink ('Literal translation', 'lit.'));
end
table.insert (out, " </small>'");
table.insert (out, args.translation);
table.insert (out, "'");
end
table.insert (out, make_category (args.code, language_name, args.nocat));
return table.concat (out); -- put it all together and done
end
return p;