模組:Lang
觀
夫斯模組之設,首為大典之殊方異語,施以定式,正其標識;其次則欲其敷彩具象,了然入目也。茲局統括{{lang}}及諸模板:Tld模板,總核源流,而所本之簿錄,皆采自萬國通規,確然有憑。
簿錄所出,具列於Module:Language/name/data及附庸諸局:
- 名與示號
- Module:Lang/data/iana languages – 出 IANA 之殊方語言副卷標註冊簿。
- Module:Language/data/ISO 639-3 – 出 sil.org 所載UTF-8字符全表。
- Module:Language/data/wp languages – 凡莫知所出者,皆彙於斯。
- 文字
- Module:Language/data/iana scripts – 亦出IANA註冊簿。
- 方域
- Module:Language/data/iana regions – 亦出IANA註冊簿。
- 流變
- Module:Language/data/iana variants – 亦出IANA註冊簿。
- 芟夷文字
- Module:Language/data/iana suppressed scripts – 亦出IANA註冊簿。
此外復有補遺之局:
- 變通及殊例
- Module:Lang/data – 蓋IANA與ISO 639-3參差不齊,或名號冗繁,或其說未宜公之於正文,則以
override(變通)之表權存其辭。 - Module:Lang/ISO 639 synonyms – 納三符之ISO 639-2、-2T、-3 於兩符之ISO 639-1。其法本乎表示語言名稱之規範。
斯局既立,則繁冗之模板:Tld、{{Language with name}}、{{Language with name and transliteration}}、{{transl}}諸模皆可廢也。且能自糾謬誤,明察失漏,俾標識無疵,以適披閱與誦讀之用。
凡有訛誤,則入:
- Category:lang與lang-xx模板紕漏(通曰「lang和lang-xx模板錯誤」)(惟正文暨主空間適用)
脩治之錄:
殊方文字格式:
--[=[
茲篇以 Lua 輔助 {{lang}}、{{lang-xx}} 及 {{transl}} 諸模板,並代曩時林林總總之從屬模板。
]=]
require('strict');
local p = {};
local initial_style_state; -- 設於 lang_xx_inherit() 及 lang_xx_italic() 之中
local getArgs = require ('Module:Arguments').getArgs;
local lang_name_table = mw.loadData ('Module:Language/name/data');
local synonym_table = mw.loadData ('Module:Lang/ISO 639 synonyms'); -- ISO 639-2/639-2T 碼轉為 639-1 碼之對照
local lang_data = mw.loadData ('Module:Lang/data'); -- 語名覆寫及轉寫提示框之數據表
local namespace = mw.title.getCurrentTitle().namespace; -- 用以辨別名態而歸類
local maint_cats = {}; -- 護理類屬咸集於此
local maint_msgs = {}; -- 護理之辭亦系乎此
local function page_exists (title)
-- 斯凾式行 #ifexist 之功
local noError, titleObject = pcall (mw.title.new, title)
if not noError then
return false
else
if titleObject then
return titleObject.exists
else
return false
end
end
end
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
察變數之有無。實則報真,虛則報假。所謂實者,存而不空之謂也(非 nil 且非空字串)。
]]
local function is_set( var )
return not (var == nil or var == '');
end
--[[--------------------------< I S _ L A T N >----------------------------------------------------------------
察文辭悉爲拉丁字、數碼與句讀與否。若然則報真,否則報假。
案:此處所謂拉丁字者,乃扣除控制字元之萬國碼(Unicode 10.0)字元,其表具列如下:
[http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] U+0020–U+007E (20 - 7E) + see note about <poem>...</poem> support
[http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] U+00A0-U+00AC, U+00C0–U+00FF (C2 A0 - C2 AC, C3 80 - C3 BF: \194\160-\194\172)
[http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] U+0100–U+017F (C4 80 - C5 BF)
[http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] U+0180–U+024F (C6 80 - C9 8F)
[http://www.unicode.org/charts/PDF/U1E00.pdf Latin Extended Additional] U+1E00-U+1EFF (E1 B8 80 - E1 BB BF)
[http://www.unicode.org/charts/PDF/U2C60.pdf Latin Extended-C] U+2C60–U+2C7F (E2 B1 A0 - E2 B1 BF)
[http://www.unicode.org/charts/PDF/UA720.pdf Latin Extended-D] U+A720-U+A7FF (EA 9C A0 - EA 9F BF)
[http://www.unicode.org/charts/PDF/UAB30.pdf Latin Extended-E] U+AB30-U+AB6F (EA AC B0 - EA AD AF)
[http://www.unicode.org/charts/PDF/UFB00.pdf Alphabetic Presentaion Forms] U+FB00-U+FB06 (EF AC 80 - EF AC 86)
[http://www.unicode.org/charts/PDF/UFF00.pdf Halfwidth and Fullwidth Forms] U+FF01-U+FF3C (EF BC 81 EF BC BC)
凡詩歌辭賦,{{lang}} 常用於 <poem>...</poem> 之中。此籤將換行符化爲詩歌剝離標記,其式若:
?'"`UNIQ--poem-67--QINU`"'?
其 '?' 實爲刪除符(U+007F, \127)。故納 '\n'(U+0010)與刪除符於拉丁字表,俾 {{lang}} 於詩歌中亦能自化斜體。
]]
function p.is_latn (text)
local latn = table.concat (
{
'[', -- 始括號
'\n\32-\127', -- 基本拉丁字與控制符
'\194\160-\194\172', -- 拉丁字一之補充
'\195\128-\195\191', --
'\196\128-\197\191', -- 拉丁字擴展甲
'\198\128-\201\143', -- 拉丁字擴展乙
'\225\184\128-\225\187\191', -- 拉丁字擴展附加
'\226\177\160-\226\177\191', -- 拉丁字擴展丙
'\234\156\160-\234\159\191', -- 拉丁字擴展丁
'\234\172\176-\234\173\175', -- 拉丁字擴展戊
'\239\172\128-\239\172\134', -- 字母表現形式
'\239\188\129-\239\188\188', -- 半形與全形
'–', -- 連結號
'—', -- 破折號
'«', '»', -- 拉丁語文常用之引號
']', -- 終括號
});
text = mw.text.decode (text, true); -- 化 HTML 實體為萬國碼字元
text = mw.ustring.gsub (text, '%[%[[^|]+|([^%]]+)%]%]', '%1'); -- 剔除維基連結,以防跨語言連結干擾
return not is_set (mw.ustring.gsub (text, latn, '')); -- 盡除拉丁字;若悉為空,則本為拉丁文也
end
--[[--------------------------< I N V E R T _ I T A L I C S >-------------------------------------------------
此式旨在反覆 args.text 內之斜體標識。其法增損首尾之斜體,以成反效。其有單撇號者,皆化作 HTML 數碼,以免誤作粗體。
首尾之維基標識,皆自 args.text 析出,而分置於表。增刪替換之功,惟賴 string.gsub()。
案:此式之用,必賴 args.text 內之標識完好無缺;若有舛錯,必生異端。
]]
local function invert_italics (source)
local invert_pattern_table = { -- 首尾標識增刪替換之則
[""]="\'\'", -- 空字串化爲斜體標識
["\'\'"]="", -- 斜體標識化爲空字串
["\'\'\'"]="\'\'\'\'\'", -- 粗體化爲粗斜體
["\'\'\'\'\'"]="\'\'\'", -- 粗斜體化爲粗體
};
local seg = {};
source = source:gsub ("%f[\']\'%f[^\']", '&'); -- 護單撇號,防作粗體解
seg[1] = source:match ('^(\'\'+%f[^\']).+') or ''; -- 取首標識(若有)
seg[3] = source:match ('.+(%f[\']\'\'+)$') or ''; -- 取尾標識(若有)
if '' ~= seg[1] and '' ~= seg[3] then -- 析其文段
seg[2] = source:match ('^\'\'+%f[^\'](.+)%f[\']\'\'+$') -- 居首尾標識之中者
elseif '' ~= seg[1] then
seg[2] = source:match ('^\'\'+%f[^\'](.+)') -- 隨首標識之後者
elseif '' ~= seg[3] then
seg[2] = source:match ('(.+)%f[\']\'\'+$') -- 居尾標識之前者
else
seg[2] = source -- 杳無標識者
end
seg[1] = seg[1]:gsub (".*", invert_pattern_table, 1); -- 依則替其首
seg[3] = seg[3]:gsub (".*", invert_pattern_table, 1); -- 依則替其尾
return table.concat (seg); -- 合而還之
end
--[[--------------------------< V A L I D A T E _ I T A L I C >------------------------------------------------
覈 |italic= 或 |italics= 之賦值。
若 |italic= 有值且允當,則報相應之 css font-style 屬性值;特例 'default' 則報 nil。
若 |italic= 未設,或其值不允,則報 nil 與 nil 紕漏辭。
若 |italic= 與 |italics= 俱設,報 nil 與 '抵觸' 紕漏辭。
諸般允當之值列下:
nil - 未設,報 nil
default - 備而不用,報 nil
yes - 勒令文辭作斜體,報 'italic'
no - 勒令文辭作正體,報 'normal'
unset - 弛其管束,字體惟外圍標記是從,報 'inherit'
invert - 弛其管束,反覆其內之斜體,報 'invert'
]]
local function validate_italic (italic, italics)
local properties = {['yes'] = 'italic', ['no'] = 'normal', ['unset'] = 'inherit', ['invert'] = 'invert', ['default'] = nil};
if italic and italics then -- 俱設則報紕漏
return nil, '抵觸:|italic= 與 |italics= 俱設';
end
return properties[italic or italics], nil; -- 報其值並附空紕漏辭
end
--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------
尋針於海,察物之在列與否。
]]
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 >------------------------------------------------
潤色 IETF 標籤,使符善式:
代碼(code):小寫
文字(script):首字大寫
地區(region):大寫
變體(variant):小寫
]]
local function format_ietf_tag (code, script, region, variant)
local out = {};
table.insert (out, code:lower());
if is_set (script) then
script = script:lower():gsub ('^%a', string.upper);
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 >--------------------------------------------------
析出 IETF 語言標籤之諸部,並報之:
主語標籤(必具) - 二三字之 IANA 語碼
文字標籤 - 四字之 IANA 文字碼
地區標籤 - 二字或三數碼之 IANA 地區碼
變體標籤 - 四數碼或五至八字之變體碼
私有標籤 - x- 冠首,繼以一至八字之私有碼;惟主語標籤可用
所析之形若下:
lang lang-variant
lang-script lang-script-variant
lang-region lang-region-variant
lang-script-region lang-script-region-variant
lang-x-private
凡所用者,皆須允當。
語碼兼具二字、三字者,升等作二字;蓋 IANA 註冊檔每遺同義之三字碼,且瀏覽器未必識三字碼也。
於 {{lang-xx}} 模板,援用 |script=, |region=, 及 |variant= 變數。
報六值。允當者報其本質;闕如者報空串;不允者報 nil;第六值為紕漏之辭(若有舛錯)或 nil。
詳參 http://www.rfc-editor.org/rfc/bcp/bcp47.txt 節 2.1
]]
local function get_ietf_parts (source, args_script, args_region, args_variant)
local code;
local script = '';
local region = '';
local variant = '';
local private = '';
if not is_set (source) then
return nil, 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 (variant 為四數碼)
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
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
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
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
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
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
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
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
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
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
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][%a%d]?[%a%d]?[%a%d]?$') then -- ll-variant
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
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
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 ('^%a%a%a?%-x%-[%a%d][%a%d]?[%a%d]?[%a%d]?[%a%d]?[%a%d]?[%a%d]?[%a%d]?$') then -- ll-x-pppppppp
code, private = source:match ('^(%a%a%a?)%-x%-([%a%d]+)$');
else
return nil, nil, nil, nil, nil, table.concat ({'語籤乖式:', source}); -- 形制乖謬,莫辨何物
end
code = code:lower(); -- 悉化小寫
if not (lang_data.override[code] or lang_name_table.lang[code]) then
return nil, nil, nil, nil, nil, table.concat ({'語文之示號莫辨:', code}); -- 語碼不允當
end
if synonym_table[code] then -- 若有 639-1 之同義碼
table.insert (maint_cats, table.concat ({'改lang與lang-xx示號為ISO 639-1|', code}));
table.insert (maint_msgs, table.concat ({'示號:', code, '改以示號:', synonym_table[code]}));
code = synonym_table[code]; -- 採同義碼
end
if is_set (script) then
if is_set (args_script) then
return code, nil, nil, nil, nil, '文籤冗贅'; -- 不得兼具標籤內之文字與 |script= 變數
end
else
script = args_script or ''; -- 採變數所賦
end
if is_set (script) then
script = script:lower(); -- 悉化小寫
if not lang_name_table.script[script] then
return code, nil, nil, nil, nil, table.concat ({'文字莫辨:', script, ',其示號為:', code});
end
end
if lang_name_table.suppressed[script] then -- 查有無遭抑之文字
if in_array (code, lang_name_table.suppressed[script]) then
return code, nil, nil, nil, nil, table.concat ({'文段:', script, ',於此示號見絀:', code});
end
end
if is_set (region) then
if is_set (args_region) then
return code, nil, nil, nil, nil, '域籤冗贅'; -- 標籤與變數不可同具
end
else
region = args_region or ''; -- 採變數所賦
end
if is_set (region) then
region = region:lower(); -- 悉化小寫
if not lang_name_table.region[region] then
return code, script, nil, nil, nil, table.concat ({'地區莫辨:', region, ',其示號為:', code});
end
end
if is_set (variant) then
if is_set (args_variant) then
return code, nil, nil, nil, nil, '變體標籤冗贅'; -- 標籤與變數不可同具
end
else
variant = args_variant or ''; -- 採變數所賦
end
if is_set (variant) then
variant = variant:lower(); -- 悉化小寫
if not lang_name_table.variant[variant] then -- 覈變體之允當與否
return code, script, region, nil, nil, table.concat ({'變體莫辨:', variant});
end
if is_set (script) then -- 若設有文字,則必爲前綴之一部
if not in_array (table.concat ({code, '-', script}), lang_name_table.variant[variant]['prefixes']) then
return code, script, region, nil, nil, table.concat ({'變體莫辨:', variant, ',屬乎示號、文字之對:', code, '-', script});
end
else
if not in_array (code, lang_name_table.variant[variant]['prefixes']) then
return code, script, region, nil, nil, table.concat ({'變體莫辨:', variant, ',其示號為:', code});
end
end
end
if is_set (private) then
private = private:lower(); -- 悉化小寫
if not lang_data.override[table.concat ({code, '-x-', private})] then -- 覈私有籤之允當與否
return code, script, region, nil, nil, table.concat ({'私有標籤莫辨:', private});
end
end
return code, script, region, variant, private, nil; -- 報其菁華;紕漏辭須爲 nil
end
--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
聚模板名、辭意、助連、紕漏類屬,以成紕漏之辭。
]]
local function make_error_msg (msg, args, template)
local out = {};
local category;
if 'transl' == template then
category = 'transl';
else
category = 'lang與lang-xx'
end
table.insert (out, table.concat ({'[', args.text or '闕如', '] '})); -- 宣示 args.text(若有)
table.insert (out, table.concat ({'<span style=\"font-size:100%; font-style:normal;\" class=\"error\">紕漏:{{', template, '}}:'}));
table.insert (out, msg);
table.insert (out, table.concat ({'([[:Category:', category, '模板紕漏|助]])'}));
table.insert (out, '</span>');
if (0 == namespace) and not is_set (args.nocat) then -- 惟條目空間始入類
table.insert (out, table.concat ({'[[Category:', category, '模板紕漏]]'}));
end
return table.concat (out);
end
--[=[-------------------------< M A K E _ W I K I L I N K >----------------------------------------------------
造維基連結;若具連結與示文,則報 [[L|D]] ;若僅具連結,則報 [[L]] ;俱闕則報空串。
]=]
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 >--------------------------------------------------
案:宜增區塊(block)之援:以 div 替 span;需以適宜之變數控之。
於斜體而言,若文爲斜體,則弗能徑作 ''{{lang|xx|text}}'' 而捨 <span/> 不用。蓋外之標記將化爲:
<i><i lang="xx">text</i></i>
而後化簡爲:
<i>text</i>
此化簡之功,超乎此模板模組之外。
是故,修繕未畢前,斜體文段必作:
<i><span lang="xx">text</span></i>
]]
local function make_text_span (code, text, rtl, style, size, language)
local span = {};
local style_added = '';
if text:match ('^%*') then
table.insert (span, '*'); -- 移原始語前綴星號於斜體之外
text = text:gsub ('^%*', ''); -- 摘去星號
end
if 'italic' == style then
table.insert (span, '<i>'); -- 啓斜體
end
table.insert (span, table.concat ({'<span lang="'})); -- 啓 <span>
table.insert (span, table.concat ({code, '\"'})); -- 添語言屬性
if rtl then
table.insert (span, ' dir="rtl"'); -- 右至左語言添方向屬性
end
if 'normal' == style then -- 遇 |italic=no
table.insert (span, ' style=\"font-style:normal;'); -- 蓋覆外圍標識
style_added = '\"'; -- 記屬性已添而未合
end
if is_set (size) then -- 遇 |size=<某物>
if is_set (style_added) then
table.insert (span, table.concat ({' font-size:', size, ';'})); -- 屬性既立則續添
else
table.insert (span, table.concat ({' style=\"font-size:', size, ';'})); -- 創設字號屬性
style_added = '\"'; -- 記屬性已添而未合
end
end
if is_set (language) then
table.insert (span, table.concat ({style_added, ' title=\"', language})); -- 啓提示框
if language:find ('languages') then
table.insert (span, '集體語文\"'); -- 集體語文
else
table.insert (span, '語文\"'); -- 獨語
end
table.insert (span, '>'); -- 閉 <span> 首標籤
else
table.insert (span, table.concat ({style_added, '>'})); -- 閉屬性與 <span> 首標籤
end
table.insert (span, text); -- 入文段
table.insert (span, '</span>'); -- 閉 <span>
if 'italic' == style then
table.insert (span, '</i>'); -- 閉斜體
end
if rtl then -- 遺緒;今既全包於 rtl,實屬無庸
table.insert (span, '‎'); -- 告覽器以右至左文段之終
end
return table.concat (span); -- 合而報之
end
--[=[-------------------------< M A K E _ C A T E G O R Y >----------------------------------------------------
案:此處有易。凡中文,則歸之[[Category:明確引用中文之條目]]。
非中文者:
若屬常用,直入[[Category:具<某語>之條目]]。
非常用者:
有類屬則歸其類。
無則入[[Category:具非中文內容之條目]]。
]=]
local function make_category (code, language_name, nocat)
local cat = {};
if (0 ~= namespace) or nocat then -- 惟條目空間始入類
return ''; -- 報空串以合之
end
table.insert (cat, '[[Category:具');
if 'zh' == code then
table.insert (cat, '明確引用中文');
elseif 'ar' == code then
table.insert (cat, '阿拉伯語')
elseif 'en' == code then
table.insert (cat, '英語')
elseif 'es' == code then
table.insert (cat, '西班牙語')
elseif 'de' == code then
table.insert (cat, '德語')
elseif 'fr' == code then
table.insert (cat, '法語')
elseif 'ja' == code then
table.insert (cat, '日語')
elseif 'bg' == code then
table.insert (cat, '保加利亞語')
elseif 'cs' == code then
table.insert (cat, '捷克語')
elseif 'da' == code then
table.insert (cat, '丹麥語')
elseif 'nl' == code then
table.insert (cat, '荷蘭語')
elseif 'et' == code then
table.insert (cat, '愛沙尼亞語')
elseif 'fi' == code then
table.insert (cat, '芬蘭語')
elseif 'el' == code then
table.insert (cat, '希臘語')
elseif 'hu' == code then
table.insert (cat, '匈牙利語')
elseif 'ga' == code then
table.insert (cat, '愛爾蘭語')
elseif 'grc' == code then
table.insert (cat, '古希臘語')
elseif 'kr' == code then
table.insert (cat, '卡努里語')
elseif 'la' == code then
table.insert (cat, '拉丁語')
elseif 'cy' == code then
table.insert (cat, '威爾斯語')
elseif 'sl' == code then
table.insert (cat, '斯洛維尼亞語')
elseif 'yue' == code then
table.insert (cat, '粵語')
elseif (page_exists ('Category:具' .. language_name .. '之條目') ) then
table.insert (cat, language_name);
else
table.insert (cat, '非中文內容');
end
table.insert (cat, '之條目]]');
return table.concat (cat);
end
--[[--------------------------< M A K E _ T R A N S L I T >----------------------------------------------------
報轉寫 <i lang=xx-Latn>...</i>,xx 爲語言代碼;否則報空串。
{{transl}} 之 |script= 變數弗為此用,乃用 |code。蓋語言文字咸列於 {{transl}} 樞紐之中,俱在數據表矣。
文字變數肇於 {{Language with name and transliteration}}。若 |script= 有設,斯函式先取之。
為防混淆,此模組及模板中,轉寫文字變數更名為 |translit-script= (斯函式中為 tscript)。
斯函式爲 lang_xx() 及 transl() 俱用:
lang_xx() 恆賦 code、language_name、translit;或賦 tscript;不賦 style。
transl() 恆賦 language_name、translit;並賦 code、tscript 其一(不兼賦);恆賦 style。
於 {{transl}} 而言,惟賦 code 始生 style。
]]
local function make_translit (code, language_name, translit, std, tscript, style)
local title;
local tout = {};
local title_table = lang_data.translit_title_table; -- 轉譯基準之表,暨其語碼、文字
if is_set (code) then -- 若賦語碼({{lang-xx}} 恆有,{{transl}} 則未必然)
if not style then -- nil 則默作斜體
table.insert (tout, "<span lang=\""); -- 用 <span>
else
table.insert (tout, table.concat ({'<span style=\"font-style:', style, '\" lang=\"'})); -- 非常規字體則造 span 標籤
end
table.insert (tout, code);
table.insert (tout, "-Latn\" title=\""); -- 轉寫恆爲拉丁文字
else
table.insert (tout, "<span title=\""); -- 若無語碼:弗設 lang= 屬性,亦非斜體(惟 {{transl}} 有之)
end
std = std and std:lower(); -- 化小寫以索表
if not is_set (std) and not is_set (tscript) then -- 若基準與文字俱闕
table.insert (tout, language_name); -- 書尋常提示語
if not language_name:find ('languages') then -- 集體語名
table.insert (tout, '語') -- 單一或宏語言
end
table.insert (tout, '轉寫'); -- 終其提示
elseif is_set (std) and is_set (tscript) then -- 若兩者俱全
if title_table[std] then -- 且基準允當
if title_table[std][tscript] then -- 且所用文字允當
table.insert (tout, table.concat ({title_table[std][tscript:lower()], '(', lang_name_table.script[tscript][1], '文)轉寫'})); -- 添提示文
else
table.insert (tout, title_table[std]['default']); -- 弗在表內則用默認;案:宜添維護類屬?
end
else
return ''; -- 基準見紕,俟發紕漏辭
end
elseif is_set (std) then -- 設基準而闕文字,則用語碼
if not title_table[std] then return ''; end -- 基準見紕,俟發紕漏辭
if title_table[std][code] then -- 若語碼在表(transl 未必有語碼)
table.insert (tout, table.concat ({title_table[std][code:lower()], '(', lang_name_table.lang[code][1], '語)轉寫'})); -- 添提示文
else -- 語碼弗符
table.insert (tout, title_table[std]['default']); -- 採默認值
end
else -- 設文字而闕基準
if title_table['no_std'][tscript] then
table.insert (tout, title_table['no_std'][tscript]); -- 取所設文字
elseif title_table['no_std'][code] then
table.insert (tout, title_table['no_std'][code]); -- 取語碼
else
if is_set (tscript) then
table.insert (tout, table.concat ({language_name, '文轉寫'})); -- 書文字提示
elseif is_set (code) then
if not language_name:find ('languages') then
table.insert (tout, '語')
end
table.insert (tout, '轉寫');
else
table.insert (tout, '轉寫');
end
end
end
table.insert (tout, '">');
table.insert (tout, translit);
if is_set (code) and not style then
table.insert (tout, "</span>"); -- 閉 span 標籤
else
table.insert (tout, "</span>");
end
return table.concat (tout);
end
--[=[-------------------------< V A L I D A T E _ T E X T >---------------------------------------------------
此式查 args.text 之旨。無爽則報空串,有誤則報紕漏之辭。所覈者:文之闕如、撇號標識之乖謬。
斜體由 |italic= 變數所司,故 args.text 內斷不應有 ''斜體'' 或 '''''粗斜體''''' 之標識。
]=]
local function validate_text (template, args)
if not is_set (args.text) then
return make_error_msg ('文字闕如', args, template);
end
if args.text:find ("%f[\']\'\'\'\'%f[^\']") or args.text:find ("\'\'\'\'\'[\']+") then -- 索四撇號或六撇號以上者
return make_error_msg ('標記乖式', args, template);
end
local style = args.italic or args.italics;
if ('unset' ~= style) and ('invert' ~=style) then
if args.text:find ("%f[\']\'\'%f[^\']") or args.text:find ("%f[\']\'\'\'\'\'%f[^\']") then -- 斜而不粗,或粗斜體
return make_error_msg ('文含斜體標記', args, template);
end
end
end
--[[--------------------------< R E N D E R _ M A I N T >------------------------------------------------------
宣示護理之辭與類屬
]]
local function render_maint(nocat)
local maint = {};
if 0 < #maint_msgs then -- 有護理辭之時
table.insert (maint, table.concat ({'<span class="lang-comment" style="font-style:normal; display:none; color:#33aa33; margin-left:0.3em">'})); -- 啓 <span>
for _, msg in ipairs (maint_msgs) do
table.insert (maint, table.concat ({msg, ' '})); -- 添辭
end
table.insert (maint, '</span>'); -- 閉之
end
if (0 < #maint_cats) and (0 == namespace) and not is_set (nocat) then -- 條目空間有類屬時
for _, cat in ipairs (maint_cats) do
table.insert (maint, table.concat ({'[[Category:', cat, ']]'})); -- 成列而入類
end
end
return table.concat (maint);
end
--[[--------------------------< P R O T O _ P R E F I X >------------------------------------------------------
若乃原始語言,文前綴以星號。吾人於此為之,俾 make_text_span() 知之,使星號居斜體標識之外(若有斜體)。若文本已有星號,則不加。
]]
local function proto_prefix (text, language_name)
if language_name:find ('^Proto%-') and not text:find ('^*') then -- 屬原始語且未冠星號
return table.concat ({'*', text}); -- 冠以星號
end
return text;
end
--[[--------------------------< L A N G >----------------------------------------------------------------------
{{lang}} 之戶樞
本無庸於 {{lang}} {{#invoke:}} 設變數
<includeonly>{{#invoke:lang|lang}}</includeonly>
諸變數皆受諸模板外框。
]]
function p.lang (frame)
local args = getArgs(frame);
local out = {};
local language_name; -- 司歸類
local subtags = {}; -- IETF 之諸子籤
local code; -- 語碼
local msg; -- 紕漏之辭
if args[1] and args.code then
return make_error_msg ('鉏鋙:{{{1}}} 與 |code=', args, 'lang');
else
args.code = args[1] or args.code; -- 尚 args.code
end
if args[2] and args.text then
return make_error_msg ('鉏鋙:{{{2}}} 與 |text=', args, 'lang');
else
args.text = args[2] or args.text; -- 尚 args.text
end
if nil == args.italic then -- nil 時以 args.italic 司之
args.italic = 'unset';
end
msg = validate_text ('lang', args); -- 覈 |text= 俱在
if is_set (msg) then -- 遇紕漏則發
return msg;
end
args.rtl = args.rtl == 'yes'; -- 化為真假:'yes' 報真,餘皆報假
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code); -- |script=, |region=, |variant= 皆不與焉,蓋宜併於 args.code
if msg then
return make_error_msg ( msg, args, 'lang');
end
args.italic, msg = validate_italic (args.italic, args.italics);
if msg then
return make_error_msg (msg, args, 'lang');
end
if is_set (subtags.script) then -- 若設文字,蓋覆 rtl
if in_array (subtags.script, lang_data.rtl_scripts) then
args.rtl = true; -- 乃右至左文
else
args.rtl = false; -- 否
end
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant); -- 依善式排布;私有者略去
if is_set (subtags.private) and lang_data.override[table.concat ({code, '-x-', subtags.private})] then
language_name = lang_data.override[table.concat ({code, '-x-', subtags.private})][1];
elseif 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]; -- 語名繁多者,取其首
end
if 'invert' == args.italic then
args.text = invert_italics (args.text)
end
-- 中文版特化部分:為非中文文字禁用繁簡轉換,中文文字與其他以漢字作為書寫系統之漢語方言文字啟用繁簡轉換。
if 'zh' == code then
args.text = args.text
elseif 'gan' == code then
args.text = args.text
elseif 'wuu' == code then
args.text = args.text
elseif 'yue' == code then
args.text = args.text
elseif 'lzh' == code then
args.text = args.text
elseif 'hsn' == code then
args.text = args.text
else
args.text = args.text
end
args.text = proto_prefix (args.text, language_name); -- 原始語文綴星號
table.insert (out, make_text_span (args.code, args.text, args.rtl, args.italic, args.size, language_name));
table.insert (out, make_category (code, language_name, args.nocat));
table.insert (out, render_maint(args.nocat)); -- 宣護理之屬
return table.concat (out); -- 畢其功
end
--[[--------------------------< L A N G _ X X >----------------------------------------------------------------
{{lang-xx}} 諸模板,惟語言代碼不可或缺。餘者皆宜書於模板呼求之中。凡有多端書寫之語,亦宜設 |script=。
為各模板擇其戶樞,俾知默認之字體。
正體:
<includeonly>{{#invoke:lang|lang_xx_inherit|code=xx}}</includeonly>
斜體:
<includeonly>{{#invoke:lang|lang_xx_italic|code=xx}}</includeonly>
餘變數受諸外框。
容納變數列下:
|code = (必) IANA 語碼
|script = IANA 文字碼;多書寫系統之語宜用;遇 |code= 之文字標籤則退讓 [尚未行]
|region = IANA 地區碼
|variant = IANA 變體碼
|text = (必)示文
|link = 布林假('no')則絕其語言之連結
|rtl = 布林真('yes')則視為右至左語
|nocat = 布林真('yes')則止其歸類;紕漏類不與焉
|italic = 布林真('yes')作斜體;假('no')作正體;未設則從 initial_style_state
|lit = 文本之直譯
|label = 'none' 則悉抑標識(語名、'轉寫'、'直譯'等)
其餘字串則代語名標識 - 自行連結之功亦隳
於容納轉寫之模板:
|translit = 轉寫文
|translit-std = 轉譯基準
|translit-script = ISO 15924 碼;退讓於 code
無名參量:
{{{1}}} 文段
{{{2}}} 轉寫文
{{{3}}} 直譯文
餘者弗許。
]]
local function _lang_xx (frame)
local args = getArgs(frame, {parentFirst= true}); -- 模板變數蓋覆 {{#invoke:}} 者
local out = {};
local language_name; -- 司宣示、連結
local category_name; -- 同上,惟留其括號消歧義
local subtags = {};
local code;
local translit_script_name;
local translit;
local translit_title;
local msg;
if args[1] and args.text then
return make_error_msg ('鉏鋙:{{{1}}} 與 |text=', args, 'lang-xx');
else
args.text = args[1] or args.text;
end
msg = validate_text ('lang-xx', args); -- 覈 |text= 且無斜體之乖
if is_set (msg) then
return msg;
end
if args[2] and args.translit then
return make_error_msg ('鉏鋙:{{{2}}} 與 |translit=', args, 'lang-xx');
else
args.translit = args[2] or args.translit
end
if args[3] and (args.translation or args.lit) then
return make_error_msg ('鉏鋙:{{{3}}} 與 |lit= 或 |translation=', args, 'lang-xx');
elseif args.translation and args.lit then
return make_error_msg ('鉏鋙:|lit= 與 |translation=', args, 'lang-xx');
else
args.translation = args[3] or args.translation or args.lit;
end
if args.links and args.link then
return make_error_msg ('鉏鋙:|links= 與 |link=', args, 'lang-xx');
else
args.link = args.link or args.links;
end
args.rtl = args.rtl == 'yes';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code, args.script, args.region, args.variant);
if msg then
return make_error_msg (msg, args, 'lang-xx');
end
args.italic, msg = validate_italic (args.italic, args.italics);
if msg then
return make_error_msg (msg, args, 'lang-xx');
end
if nil == args.italic then
if is_set (subtags.script) then
if 'latn' == subtags.script then
args.italic = 'italic'; -- |script=Latn; 設斜體
else
args.italic = initial_style_state; -- 非拉丁文;從 initial_style_state
end
else
args.italic = initial_style_state; -- 皆未設;從 initial_style_state
end
end
if is_set (subtags.script) then
if in_array (subtags.script, lang_data.rtl_scripts) then
args.rtl = true;
else
args.rtl = false;
end
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant);
if is_set (subtags.private) and lang_data.override[table.concat ({code, '-x-', subtags.private})] then
language_name = lang_data.override[table.concat ({code, '-x-', subtags.private})][1];
elseif lang_data.override[args.code:lower()] then
language_name = lang_data.override[args.code:lower()][1];
elseif lang_data.override[code] then
language_name = lang_data.override[code][1];
elseif not is_set (subtags.variant) then
if lang_name_table.lang[code] then
language_name = lang_name_table.lang[code][1];
end
else -- 案:取變體名果善乎?
if lang_name_table.variant[subtags.variant] then
language_name = lang_name_table.variant[subtags.variant]['descriptions'][1];
end
end
category_name = language_name; -- 類名留括號
language_name = language_name:gsub ('%s+%b()', ''); -- 語名去括號與消歧義
if args.label then
if 'none' ~= args.label then
table.insert (out, table.concat ({args.label, ':'})); -- 自定標識
end
else
if 'no' == args.link then
table.insert (out, language_name); -- 語名無連結
else
table.insert (out, make_wikilink (language_name)); -- 語名設連
end
table.insert (out, ':'); -- 割斷
end
if 'invert' == args.italic then
args.text = invert_italics (args.text)
end
-- 中文版特化部分:為非中文文字禁用繁簡轉換,中文文字與其他以漢字作為書寫系統之漢語方言文字啟用繁簡轉換。
if 'zh' == code then
args.text = args.text
elseif 'gan' == code then
args.text = args.text
elseif 'wuu' == code then
args.text = args.text
elseif 'yue' == code then
args.text = args.text
elseif 'lzh' == code then
args.text = args.text
elseif 'hsn' == code then
args.text = args.text
else
args.text = args.text
end
args.text = proto_prefix (args.text, language_name);
table.insert (out, make_text_span (args.code, args.text, args.rtl, args.italic, args.size))
if is_set (args.translit) and not p.is_latn (args.text) then -- 有轉寫且文非全拉丁
args.translit = args.translit
table.insert (out, ','); -- 以逗號間之
if 'none' ~= args.label then
table.insert (out, '<small>');
if lang_name_table.script[args['translit-script']] then
translit_script_name = lang_name_table.script[args['translit-script'][1]];
else
translit_script_name = language_name; -- 否則退求語名
end
translit_title = mw.title.makeTitle (0, table.concat ({translit_script_name, '羅馬化'}));
if translit_title.exists and ('no' ~= args.link) then
table.insert (out, make_wikilink ((translit_script_name or language_name) .. '羅馬化', '轉寫'));
else
table.insert (out, '轉寫');
end
table.insert (out, ':</small>');
end
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 ({'轉譯基準不允:\'', args['translit-std'] or '[闕如]'}), args, 'lang-xx');
end
end
if is_set (args.translation) then -- 直譯
table.insert (out, ',');
if 'none' ~= args.label then
table.insert (out, '<small>');
if 'no' == args.link then
table.insert (out, '直譯');
else
table.insert (out, make_wikilink ('直譯'));
end
table.insert (out, ":</small>");
end
table.insert (out, table.concat ({args.translation}));
end
table.insert (out, make_category (code, category_name, args.nocat));
table.insert (out, render_maint(args.nocat));
return table.concat (out);
end
--[[--------------------------< L A N G _ X X _ I T A L I C >--------------------------------------------------
呼 lang_xx_italic() 諸 {{lang-xx}} 模板之戶樞。設初始字體爲斜體。
]]
function p.lang_xx_italic (frame)
initial_style_state = 'italic';
return _lang_xx (frame);
end
--[[--------------------------< L A N G _ X X _ I N H E R I T >------------------------------------------------
呼 lang_xx_inherit() 諸模板之戶樞。設初始字體爲承繼(inherit)。
]]
function p.lang_xx_inherit (frame)
initial_style_state = 'inherit';
return _lang_xx (frame);
end
--[[--------------------------< N A M E _ F R O M _ C O D E >--------------------------------------------------
若 IETF 語言標籤允當,則報其語言之名;否則報空串。
{{lang}} 與 {{lang-xx}} 所容之合碼,咸爲此函式所援。
]]
function p.name_from_code (frame)
local subtags = {};
local raw_code = (frame.args and frame.args[1]) or frame;
local code;
local msg;
local language_name = '';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (raw_code);
if msg then
return '';
end
if lang_data.override[raw_code:lower()] then
language_name = lang_data.override[raw_code:lower()][1];
elseif lang_data.override[code] then
language_name = lang_data.override[code][1];
elseif not is_set (subtags.variant) then
if lang_name_table.lang[code] then
language_name = lang_name_table.lang[code][1];
end
else
if lang_name_table.variant[subtags.variant] then
language_name = lang_name_table.variant[subtags.variant]['descriptions'][1];
end
end
language_name = language_name:gsub ('%s+%b()', '');
return language_name;
end
--[[--------------------------< T R A N S L >------------------------------------------------------------------
擬代 {{transl}} 模板者
]]
function p.transl (frame)
local args = getArgs(frame); -- 無 {{#invoke:}} 參量
local title_table = lang_data.translit_title_table;
local language_name;
local translit;
local script;
local msg;
if is_set (args[3]) then -- 形如 {{transl|code|standard|text}}
args.text = args[3];
args.translit_std = args[2] and args[2]:lower();
if not title_table[args.translit_std] then
return make_error_msg (table.concat ({'轉譯基準莫辨:', args.translit_std}), args, 'transl');
end
else
if is_set (args[2]) then -- 形如 {{transl|code|text}}
args.text = args[2];
else
if args[1] and args[1]:match ('^%a%a%a?%a?$') then -- args[2] 既無,args[1] 果爲語碼乎?
return make_error_msg ('文字闕如', args, 'transl'); -- args[1] 爲碼,是缺文字也
else
args.text = args[1]; -- args[1] 非碼,俟報紕漏
return make_error_msg ('語文示號闕如', args, 'transl');
end
end
end
if is_set (args[1]) then -- IANA 語碼或 ISO 15924 碼
if args[1]:match ('^%a%a%a?%a?$') then
args.code = args[1]:lower();
else
return make_error_msg (table.concat ({'語文示號莫辨:', args[1]}), args, 'transl');
end
else
return make_error_msg ('語文示號闕如', args, 'transl');
end
args.italic, msg = validate_italic (args.italic, args.italics);
if msg then
return make_error_msg (msg, args, 'transl');
end
if 'italic' == args.italic then -- 遇 |italic=yes
args.italic = nil; -- 置為 nil
end
if lang_data.override[args.code] then
language_name = lang_data.override[args.code][1];
elseif lang_name_table.lang[args.code] then
language_name = lang_name_table.lang[args.code][1];
elseif lang_name_table.script[args.code] then
language_name = lang_name_table.script[args.code][1];
script = args.code;
args.code = '';
else
return make_error_msg (table.concat ({'語文示號莫辨:', args.code}), args, 'transl');
end
return make_translit (args.code, language_name, args.text, args.translit_std, script, args.italic);
end
return p;