维基百科
wuuwiki
https://wuu.wikipedia.org/wiki/%E5%B0%81%E9%9D%A2
MediaWiki 1.47.0-wmf.14
first-letter
Media
Special
Talk
User
User talk
Wikipedia
Wikipedia talk
File
File talk
MediaWiki
MediaWiki talk
Template
Template talk
Help
Help talk
Category
Category talk
Portal
Portal talk
TimedText
TimedText talk
模块
模块讨论
Event
Event talk
大和人
0
31876
398098
398088
2026-08-06T17:51:20Z
Truherkimer
246589
使用的照片中包含一张未经许可发布的私人公民家庭照片(右下角的五口之家照片)。因此,为了保护其隐私,该照片已被删除。
398098
wikitext
text/x-wiki
'''大和人'''(日文:和人,假名:<span lang="ja" dir="ltr">わじん</span>)是[[东亚]][[日本列岛]]丄向个一个族群,人口一亿两千万。以[[百越]]、[[东夷]]作为主体个[[渡来人]]搭本身居住立在岛丄个原住民混合形成。在习俗,语言浪,搭东亚周边个[[韩人]],[[吴越人]],[[琉球人]]等統有得相似之处。[[大和人]]多数信奉[[佛教]]搭[[神道教]],語言方面通用[[日语]]标准语搭各處个方言。
[[Category:日本人]]
ihmr0whtxu9owg8hnrg1yub654vzj7g
詹姆斯·卡梅隆
0
37047
398097
346407
2026-08-06T17:02:53Z
~2026-43317-47
246949
撤销[[Special:Contributions/源義信|源義信]]([[User talk:源義信|讨论]])个版本[[Special:Diff/346407|346407]]
398097
wikitext
text/x-wiki
'''詹姆斯·弗朗西斯·卡梅隆'''(英语:James Francis Cameron,1954年8月16日-)是一位[[加拿大]][[电影]]导演,擅长以极高个预算拍摄动作片搭子科幻电影,主题往往试图探讨人搭科技之间个关系。渠个代表作《泰坦尼克号》(1997)搭《[[阿婆多罗]]》(Avatar,2009)乃朝仍旧是世界电影史上票房前两名个作品。
k2i02mbvddi1pofsttoijaoohezls0w
上海公共交通卡
0
37214
398099
397366
2026-08-07T00:17:56Z
InternetArchiveBot
83785
Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.5
398099
wikitext
text/x-wiki
'''上海公共交通卡'''(交通一卡通),上海市民通常称其为“公交卡”、“交通卡”,是[[上海市人民政府]]个一项实事工程,覆盖全上海各类交通系统(公交、轨道交通、出租、轮渡搭子磁悬浮列车),由[[上海久事集团]]个子公司上海公共交通卡股份有限公司发行<ref>{{cite news |title=用微信先乘车后付费 上海公共交通乘车码上线 |url=http://finance.china.com.cn/news/20180615/4669695.shtml |accessdate=2021-11-09 |work=中国网 |archive-date=2021-11-09 |archive-url=https://web.archive.org/web/20211109100636/http://finance.china.com.cn/news/20180615/4669695.shtml |dead-url=no |archivedate=2021-11-09 |archiveurl=https://web.archive.org/web/20211109100636/http://finance.china.com.cn/news/20180615/4669695.shtml }}</ref><ref>{{cite news |title=上海公交扫码乘车微信小程序即将上线 |url=http://www.cnr.cn/shanghai/tt/20180613/t20180613_524268986.shtml |accessdate=2021-11-09 |work=央广网 |archive-date=2021-11-09 |archive-url=https://web.archive.org/web/20211109204130/http://www.cnr.cn/shanghai/tt/20180613/t20180613_524268986.shtml |dead-url=no }}</ref>,最早一版是勒拉1999年12月27号发行个。
== 历史概况 ==
1998年9月25号,[[中共上海市委]]、[[上海市人民政府]]会议决定建设金融IC卡、城市交通IC卡、市民保障IC卡“一卡通”工程项目。1999年12月27号,上海东方交通卡股份有限公司推出上海公共交通卡,首先勒垃[[上海地铁1号线|地铁一号线]]、11条公交线路搭仔一隻摆渡口试运行;2000年4月开始推广到[[差头]];2000年11月份覆盖到[[上海地铁2号线|地铁二号线]]。[[P+R停车场]]、[[高速公路]]收费、汽车加油咾啥个勒垃上海也好刷交通卡<ref>{{cite web|title = 公司大事记 |publisher = 上海公共交通卡股份有限公司|date = |url = http://www.sptcc.com/Load_gongsijieshao.html#dashiji|accessdate = 2017-12-17|archive-date = 2020-01-27|archive-url = https://web.archive.org/web/20200127185850/http://www.sptcc.com/Load_gongsijieshao.html#dashiji|dead-url = no}}</ref>。
== 发行种类 ==
上海公共交通卡发行过个卡种有下头底能<ref>{{cite web |title = 全部产品 |publisher = 上海公共交通卡股份有限公司 |date = |url = http://www.sptcc.com/Load_quanbuchanpin.html |accessdate = 2017-12-17 }}</ref>:
* 普通卡(现在发个是2020年6月底推出个红颜色版普通卡<ref>{{Cite web|title=官宣:上海交通卡(交联版)普通卡将于 6 月底发布|url=https://www.ithome.com/0/484/247.htm|accessdate=|author=|date=|format=|publisher=|language=}}</ref>,[[交通联合|全国交通一卡通互联互通]]、[[全国城市一卡通互联互通]]双标准;老底子有紫颜色版普通卡(2012年7月16号推出<ref>{{cite web |title = 上海新增紫色交通卡本月起售 可在昆山、杭州使用 |publisher = sina.com |date = 2012-07-18 |url = http://sh.sina.com.cn/news/b/2012-07-18/08213558.html |accessdate = 2012-07-18 |language = zh }}</ref>,[[全国城市一卡通互联互通]]标准)、绿颜色(1999年首次发行)、黄颜色(2005年首次发行)、红颜色(2007年首次发行)、蓝颜色(2008年首次发行)版普通卡,侪停售哉):买卡要付20元押金(2007年年底前30元)。
* 纪念卡:特定节日、事件或者其他情况限量发行,没押金,卖出去退弗了个。
* 异型卡:长唻弗是张卡片个交通卡,限量发行,没押金,卖出去退弗了个。
* [[手表]]卡:长唻赛过手表形状个交通卡,好带勒手臂膊浪<ref>{{cite web|title = 手提式读卡器读不了手表交通卡?疑与芯片有关|publisher = 东方网|date = 2009年6月1日|url = http://sh.eastday.com/qtmt/20090601/u1a580986.html|accessdate = 2017-12-17|archivedate = 2020-10-03|archiveurl = https://web.archive.org/web/20201003161934/http://sh.eastday.com/qtmt/20090601/u1a580986.html}}</ref>。
* 银行联名卡:帮银行合作发行个,比方讲[[交通银行]]个“太平洋·交通一卡通”联名卡、[[招商银行]]个“上海交通IC联名普卡”、[[深圳发展银行]]个“上海青年卡”、[[上海农商银行]]个工会卡、[[中国建设银行|建设银行]]个“长三角畅行龙卡”<ref>{{Cite web|title=建行长三角龙卡 一卡畅行长三角|url=http://finance.sina.com.cn/stock/relnews/hk/2020-07-30/doc-iivhvpwx8293730.shtml|accessdate=|author=|date=|format=|publisher=|language=}}</ref>。
* 保通卡:帮[[中国太平洋保险]]联合推出,70岁以上老年人用个,要每隻号头付保费。非高峰时段,除开跑高速公路个线路、机场线、旅游线、[[上海磁悬浮线|磁浮线]],侪好无限次乘<ref>{{cite news |title=6月26日起老年人乘地铁需购票 “保通卡”即将启用 |url=http://news.sina.com.cn/c/2016-06-20/doc-ifxtfmrp2407569.shtml |publisher=新民网 |date=2016-06-20 |accessdate=2016-06-21 }}</ref>。伊个前身是社会保障卡—敬老卡<ref>{{cite news |title=“敬老卡”免费乘公交周日终止 |url=http://difang.gmw.cn/newspaper/2016-06/20/content_113384084.htm |publisher=东方早报 |date=2016-06-20 |accessdate=2016-06-20 |archivedate=2016-07-01 |archiveurl=https://web.archive.org/web/20160701084134/http://difang.gmw.cn/newspaper/2016-06/20/content_113384084.htm }}</ref>。
* 手环交通卡:2015年11月24号,帮凤凰云科技(北京)有限公司合作推出,除开做交通卡,还好记录运动、检测睡眠、显示辰光<ref>{{cite news|title=上海将推出地铁公交通用手环交通卡|url=http://zizhan.mot.gov.cn/zhuantizhuanlan/gonglujiaotong/gongjiaods/jingyanjl/201511/t20151123_1930802.html|publisher=华西都市报|date=2015-11-17|accessdate=2017-12-17}}{{Dead link|date=2018年7月 |bot=InternetArchiveBot |fix-attempted=yes }}</ref>。
* 手机交通卡:通过手机里向个芯片,拿交通卡功能集成到有[[近场通信|NFC]]功能个智能手机丄,刷手机就好刷卡。另外还好通过手机自家个支付程序,或者上海公交卡app开通虚拟公交卡<ref>{{cite news|title=213款手机可在上海“变身”交通卡 与实体卡享受同样优惠|url=http://www.guancha.cn/industry-science/2017_10_13_430672.shtml|publisher=观察者|date=2017-10-13|accessdate=2017-12-17}}</ref><ref>{{cite news|title=苹果发iOS 11.3版:iPhone支持刷公交卡及电池管理|url=http://news.cctv.com/2018/03/30/ARTIFVAMwreKb7IClXiMmRCQ180330.shtml|publisher=中国新闻网|date=2018-03-30|accessdate=2018-03-30}}</ref>。老底子还推出过2.4G手机钱包卡,现在停用哉<ref>{{cite news|title=关于上海地铁关闭2.4G手机钱包通道的公告|url=http://www.10086.cn/aboutus/news/pannounce/sh/index_detail_7936.html?id=7936|publisher=中国移动|date=2014-08-11|accessdate=2017-12-17|archivedate=2018-01-30|archiveurl=https://web.archive.org/web/20180130204427/http://www.10086.cn/aboutus/news/pannounce/sh/index_detail_7936.html?id=7936}}</ref>。
* 手机乘车码:是交通卡公司帮[[腾讯公司]]、[[支付宝]]、[[中国银联]]合作推出个乘车码,通过[[微信]]小程序“[[腾讯乘车码]]”、[[支付宝]]“上海公交”、[[银联云闪付]]乘车码,扫码付钞票,享受公交换乘优惠。当中微信乘车码勒垃2018年6月份就推出哉,支付宝乘车码2018年11月份推出个,同年12月份开通云闪付乘车码<ref name=thepaper>{{cite news|title=上海公交乘车码今日正式上线:用微信小程序,可先乘车后付费|url=https://www.thepaper.cn/newsDetail_forward_2196904|publisher=澎湃新闻|date=2018-06-15|accessdate=2018-06-15}}</ref><ref>{{cite news|title=上海公交上线支付宝刷码乘车|url=http://sh.eastday.com/m/20181113/u1ai11985055.html|publisher=东方网|date=2018-11-13|accessdate=2018-11-14|archivedate=2019-04-17|archiveurl=https://web.archive.org/web/20190417113743/http://sh.eastday.com/m/20181113/u1ai11985055.html}}</ref><ref>{{cite news|title=公交乘车码再添“云闪付”|url=http://www.shanghai.gov.cn/nw2/nw2314/nw2315/nw4411/u21aw1356456.html|publisher=解放日报|date=2018-12-29|accessdate=2019-01-28}}</ref>。[[中国建设银行]]、[[中国工商银行]]咾啥个也帮上海公共交通卡合作推出乘车码产品。乘车码好用来乘公交(含[[张江有轨电车]]、[[临港中运量1号线]])、摆渡(含崇明三岛轮渡)、[[上海地铁]](含金山铁路、磁浮;2022年12月3号前,乘[[上海地铁]]、磁浮要用[[Metro大都会]])。2022年12月3号开始,乘车码覆盖上海地铁系统,勒垃[[随申办]]里向出来了隻集成上海公共交通卡乘车码个“[[随申码]]”。2023年开始,[[上汽集团]]、[[上海久事]]、[[申通地铁]]咾啥上海国企设立“[[随申行]]”公司,除开提供乘车码“随申码”,还提供19.8块一张个日票,24小时里向乘上海地铁、公交、摆渡无限趟<ref>{{cite web|url=https://new.qq.com/rain/a/20230927A09MU700|title=明天起!您可以24小时不限次乘坐公交、地铁、轮渡!上海MaaS系统上线“联程日票”|author=上海交通|date=2023-09-27|website=腾讯网}}</ref>,当中同一部公交车30分钟里向只好用一趟,地铁要间隔5分钟,黄浦江摆渡乘坐间隔10分钟以上,每2個钟头旁顶乘2趟<ref>{{cite web|url=https://www.shmaas.cn/magic/dist/c2c4921b5894b5552ed0bd37be11e557/index.html|title=随申行联程日票使用须知|website=随申行|accessdate=2023-09-27}}</ref>。2024年1月20号推出47块8个联程日票三日票、85块8个联程日票七日票<ref>{{cite web|url=https://mp.weixin.qq.com/s/ccg39U1-lSJmHLtxnuPFCg|title=“随申行”联程日票(三日票/七日票)上线,陪你兜遍上海 |date=2024-01-20|author=随申行订阅号|website=微信公众平台|accessdate=2024-01-20}}</ref>。
实体卡方面,[[上海都市旅游卡]]也有交通卡功能,优惠政策同交通卡。
=== 透支 ===
当卡里向钞票还是正数,必过比要付个钞票少个辰光,好透支一趟。<ref>{{cite|url=http://xwwb.eastday.com/eastday/node29/node168/node13839/u1a165857.html|publisher=[[新闻晚报]]社|website=东方网|title=公交车司机不知交通卡可透支 卡资显示为负就不能透支|access-date=2018-04-30|archive-date=2017-12-04|archive-url=https://web.archive.org/web/20171204223002/http://xwwb.eastday.com/eastday/node29/node168/node13839/u1a165857.html|dead-url=yes}}</ref>
== 买卡充钞票 ==
[[File:Concourse of L1 Shanghai Railway Station (20170910175757).jpg|thumb|200px|[[上海地铁]][[上海火车站站]]个交通卡服务站(图左面)]]
[[File:Shanghai Public Transport Card TVM at Nenjiang Road Station.jpg|thumb|200px|交通卡自助充值机]]
乃朝,九江路服务中心、陆家浜路服务中心、[[上海地铁]]17隻自营人工服务网点有得上海公共交通卡全业务人工服务。另外勒垃全上海好德、可的、良友咾啥个1300多家便利店、[[中国邮政]]500多隻服务网点、大部分[[浦发银行]]、部分公交公司、差头公司、摆渡站头咾啥个有代理人工服务网点,提供交通卡现金售卡、充值业务个人工服务<ref name=xwcb>{{cite news|title=充交通卡难?年轻人也这样认为|url=http://newspaper.jfdaily.com/xwcb/html/2017-02/11/content_243922.htm|publisher=新闻晨报|date=2017-02-11|accessdate=2017-12-17}}</ref><ref>{{cite web |title=上海公共交通卡 服务网点 |url=https://www.sptcc.com/Load_fuwuwangdian.html#fwwd?pRfwwd_a11}}</ref>。2018年1月25号,上海个[[来伊份]]门店正式提供交通卡购卡、充值业务<ref>{{cite news|title=来伊份开通购卡充值消费服务|url=http://www.sctcd.com/newscontent.html/2761|publisher=上海都市旅游卡|date=2018-02-06|accessdate=2018-02-19|archivedate=2020-11-03|archiveurl=https://web.archive.org/web/20201103093406/http://www.sctcd.com/newscontent.html/2761}}</ref>。
2016年12月25号,上海地铁全网络100多座车站新增加公共交通卡自助充值机155台,原本个客服中心人工购卡、充值服务也取消哉,只支持[[银行卡]]、[[支付宝]](後来新增加[[微信]]支付)付钞票,部分市民,特谓是对自助充值方式弗熟悉个中老年人,邪气弗满意,认为增加交通卡冲钞票个困难,上海市人大代表[[史秋琴]]还提出书面意见<ref name=xhw>{{cite news |title=沪地铁多车站取消人工充值服务后 交通卡充值障碍重重? |url=http://sh.xinhuanet.com/2017-02/07/c_136037206.htm |publisher=看看新闻网 |date=2017-02-07 |accessdate=2017-12-17 |archivedate=2017-12-25 |archiveurl=https://web.archive.org/web/20171225203016/http://sh.xinhuanet.com/2017-02/07/c_136037206.htm }}</ref><ref>{{cite news|title=上海人大代表:地铁站取消人工充值,有老人奔赴几公里外充钱|url=http://www.thepaper.cn/newsDetail_forward_1603261|publisher=澎湃新闻|date=2017-01-18|accessdate=2017-12-17}}</ref>。故咾,上海公共交通卡公司组织技术力量,优化自助服务设备个操作界面、操作流程,勒垃地铁站头发操作手册,提供相关个服务指南<ref name=xwcb/>。2017年12月份,经交通卡公司、申通地铁集团共同协商,上海地铁恢复50隻车站个交通卡人工服务<ref>{{cite news |title=交通卡人工充值改机器充值,老人说不方便,沪已恢复50个地铁站人工服务 |url=http://www.jfdaily.com/news/detail?id=74782 |publisher=上观新闻 |date=2017-12-23 |accessdate=2017-12-23 }}</ref>。
2017年12月28号,上海交通卡公司勒垃[[上海公交71路|71路支线]]丄头一趟试点交通卡乘车二维码支付<ref>{{cite news|title=上海多条公交线试点扫码乘车,预计年内全市铺开|url=https://www.thepaper.cn/newsDetail_forward_1933154?_t_t_t=0.20140051912557422|publisher=上海发布|date=2018-01-03|accessdate=2018-01-03}}</ref>。
2018年3月29号,Apple宣布[[Apple Pay]]支持上海交通卡,大多数[[iPhone]]、[[Apple Watch]]用户好直接勒垃钱包app里向开通上海公共交通卡虚拟卡,望里向头冲钞票咯直接用。<ref>{{Cite news|url=https://support.apple.com/zh-cn/HT208539|title=在北京和上海使用 Apple Pay 快捷交通卡功能|newspaper=Apple Support|accessdate=2018-04-02|language=zh-CN}}</ref>
2018年6月15号,[[上海久事集团]]宣布帮腾讯公司达成战略合作,上线“上海公共交通乘车码”,乘客好通过[[微信小程序]]打开乘车码,扫乘车码乘公交车,享受公交换乘优惠。到10月底[[中国国际进口博览会]]开幕前,上海市公交车辆全覆盖<ref name=thepaper/>。
除开自助充值机,用户还好勒垃“上海交通卡”手机App或者[[支付宝]]里向直接畀交通卡冲钞票。
== 用卡范围 ==
[[File:New card and QR Code reader on the bus in Shanghai.jpg|200px|thumb|装有二维码扫描区个新式公交车刷卡器]]
[[File:Shanghai Metro Loushanguan Rd Station Vending Machine.jpg|200px|thumb|好用上海公交卡搭仔[[银联云闪付]]个[[自动售货机]]]]
勒垃上海,交通卡好用垃地铁、公交、[[差头]]、摆渡、[[P+R|P+R停车]]、[[加油站]]、[[高速公路]]高头,甚至好勒部分[[自动售货机]]丄买饮料。
除开箇眼勒垃上海个用法,上海公共交通卡也好勒垃外地用,必过弗同辰光个卡分两隻标准,使用范围也弗一样。
=== 城市一卡通互联互通 ===
{{main|全国城市一卡通互联互通}}
交通卡丄有City Union标识个,就表示箇卡参加住建部[[全国城市一卡通互联互通|一卡通互联互通工程]]。所有紫颜色个上海公共交通卡,外加U开头个11位纪念卡侪符合一卡通互联互通工程标准,理论丄好勒垃几十座城市用,实际浪向只好勒垃[[长三角]]部分城市用。
2002年10月1号,上海公共交通卡帮[[无锡太湖交通卡]]正式联网,上海、无锡成为中国头一批公共交通卡城际互联个城市。2017年5月1号开始,上海全面关脱对原有无锡交通卡互联互通个应用支持。
2003年4月份,上海公共交通卡好垃[[杭州]][[出租车]]浪用;2003年10月份,上海公共交通卡帮无锡太湖交通卡好勒垃[[苏州]]用;2009年,改造仔个上海交通卡收费系统兼容符合建设部最新标准个非接触式[[CPU卡]];2009年11月份,上海公共交通卡好勒垃[[大丰区|大丰]]个差头丄用,还勒垃大丰推出上海公共交通卡大丰卡,使用范围帮上海公共交通卡基本丄一模一样<ref>{{cite web |title = 上海交通卡"通"到江苏大丰(原载《新闻晨报》) |publisher = eastday.com |date = 2009-11-11 |url = http://xwcb.eastday.com/c/20091111/u1a654984.html |accessdate = 2009-11-12 |language = zh |archive-date = 2013-07-06 |archive-url = https://web.archive.org/web/20130706061645/http://xwcb.eastday.com/c/20091111/u1a654984.html |dead-url = no |archivedate = 2013-07-06 |archiveurl = https://web.archive.org/web/20130706061645/http://xwcb.eastday.com/c/20091111/u1a654984.html }}</ref>
2012年7月份,上海公交卡公司宣布,新发行个紫色普通卡帮卡号U开头个11位纪念卡是CPU卡,好勒垃建设部互联互通协议个宁波、绍兴、湖州、台州、常熟等地方用,必过弗好勒垃现有第一代逻辑加密卡互通城市用,反过来也一样<ref>{{Cite web |url=http://www.sptcc.com/news_detail.php?id=937 |title=新发上海CPU交通卡将可至宁波、绍兴等长三角五城市使用 |accessdate=2012-07-22 |archivedate=2012-10-20 |archiveurl=https://web.archive.org/web/20121020040514/http://www.sptcc.com/news_detail.php?id=937 }}</ref>。
2012年7月27号,全国城市一卡通互联互通开通仪式勒垃绍兴举行,头一批互通城市是上海、宁波、绍兴、湖州、台州、常熟、兰州、白银,需要调成新个CPU卡才支持互联互通<ref>{{Cite web |url=http://news.zgkqw.com/news/system/2012/07/28/010188523.shtml |title=8城市公交卡明起互联互通 宁波现有公交卡暂不互通 |accessdate=2012-07-28 |archivedate=2019-05-12 |archiveurl=https://web.archive.org/web/20190512033529/http://news.zgkqw.com/news/system/2012/07/28/010188523.shtml }}</ref>。
==== 异地使用说明 ====
* '''第一代逻辑加密卡(M1卡)''':绿色、黄色、红色交通卡,卡号是数字开头个纪念交通卡、异形交通卡,已停售。2018年12月31号前,好勒垃[[无锡]]、[[昆山市|昆山]]、[[常熟]]、[[阜阳]]、[[苏州]](公交)、[[杭州]](部分出租车)、[[南宁]](海博差头)、[[大丰]](车头)、[[舟山]]用;2019年1月1号开始,交通卡公司只承诺保留苏州个单向互联互通,帮其他城市个逻辑加密卡互联互通侪关脱<ref name="jthl">{{cite web |title=服务全国互联互通事业,交通卡公司迈出坚实一步(新闻稿) |url=http://www.sptcc.com/Load_jiaotongkagonggao.html#xinwen?jtk_newGG/newGG_139.json |website=上海公共交通卡股份有限公司 |accessdate=2018-12-28 |||date=2018-12-26 }}</ref>。生怕两种互联互通模式(CPU卡搭仔M1卡)对城市通卡管理产生影响,[[淮南]]停脱M1卡个互联互通。2017年6月30号开始么,[[无锡]]、[[淮南]]、[[阜阳]]个M1卡也勿好勒垃上海用哉。<ref>{{cite web |title=上海交通卡异地互通范围调整,来看五色交通卡最新互通城市 |url=http://news.163.com/17/0605/09/CM5HEH5000018AOR.html |website=news.163.com |accessdate=2018-12-28 }}</ref>
* '''过渡卡''':蓝色交通卡搭仔字母“C”开头个纪念卡、异型卡。只好垃上海、昆山用。
* '''第二代CPU卡''':紫色交通卡、11位卡号是字母“U”开头个纪念交通卡、异形交通卡。理论丄好勒垃太仓(公交)、金华城区(公交)、宜兴(公交)、宁波(公交)、绍兴(公交)、湖州(公交)、台州(公交)、常熟(公交)、昆山(公交)、江阴(公交)、淮安(公交)、启东、无锡(公交)、南通(公交)、泰州(公交)、长兴(公交)、舟山(公交)、嘉兴(公交)、义乌(公交)、温州(公交、轮渡)用(注:部分城市完全切换到[[交通联合]]仔么,[[City Union]]协议停脱哉,上海第二代CPU卡就呒办法垃伊边壗用哉)<ref>{{cite web |title = 新发上海CPU交通卡将可至宁波、绍兴等长三角五城市使用 |publisher = 上海公共交通卡股份有限公司 |date = 2012-07-10 |url = http://www.sptcc.com/news_detail.php?id=937 |accessdate = 2012-11-22 |language = zh |archivedate = 2012-10-20 |archiveurl = https://web.archive.org/web/20121020040514/http://www.sptcc.com/news_detail.php?id=937 }}</ref>。
交通卡只好异地使用,弗允许异地充卡。
=== 全国交通一卡通互联互通 ===
2019年1月1号开始,全国所有带“[[交通联合]]”标识个卡(包括先前发行个“申城通”卡)好勒垃上海所有支持刷上海公共交通卡个公交汽电车丄用<ref name="jthl" />。同年9月28号,勒垃陆家浜路服务中心,正式发行头一款非试运行个交通联合版上海公共交通卡。2019年12月26号,上海公共交通卡公司推出交通联合首发纪念试运行卡,同时享受上海公交换乘优惠。2020年1月1号开始,全国所有带“交通联合”标志个公共交通卡好勒垃上海公交、地铁、轮渡丄用,必过弗好勒垃上海充卡咯享受换乘优惠<ref>{{cite web|title=一卡在手,走遍全国!交通联合首发纪念试运行卡明天发行啦|url=http://wenhui.whb.cn/zhuzhan/cs/20191225/310688.html|accessdate=2019-12-25|agency=文汇客户端|date=2019-12-25|author=张晓鸣}}</ref>,同年6月底发布交联版普通卡<ref>{{cite news |title=新版上海交通卡6月发布可畅行全国275个城市 亮点一览 |url=http://sh.sina.com.cn/news/2020-04-26/detail-iircuyvh9911600.shtml |accessdate=2020-04-28 |work=上海交通 }}</ref>。
2021年5月10号,上海公共交通卡公司勒垃Apple Pay上线全国交联版上海交通卡<ref>{{cite web |author1=任天宝 |title=Apple Pay支持“上海交通卡·全国交联版”,可通行全国300余城地铁、公交! |url=https://wap.xinmin.cn/content/31953304.html |website=手机新民网 |publisher=新民晚报 |access-date=2022-01-11 }}</ref>,必过弗好刷差头搭仔高速公路丄付钞票。
2023年6月20号开始,[[松江有轨电车]]完成对闸机个改造,支持外地个带“交通联合”标志个交通卡<ref>{{cite web|url=https://mp.weixin.qq.com/s?src=11×tamp=1688045045&ver=4620&signature=Oau70GmpHd0XbD9AYndcy49o4L*8yo4rbNopeEOcilg7R*3J5KLKfOY3gKuL40wY57TLsLs9*x-Tapt4NWHCh0e4-6kJ8KVx8Quf2JPqxpHrSmKXi2xhIt61Hw5s0H**|title=松江有轨电车检票闸机完成升级改造 |website=微信公众平台|date=2023-06-19|author=松江现代有轨电车|accessdate=2023-06-29}}</ref>。
== 优惠政策 ==
* [[上海公交]]:勒垃乘公交或轨道交通刷卡个120分钟里向换乘公交,搭仔乘公交刷卡120分钟以後乘轨道交通个,优惠1块,勒垃公交车读卡器丄,享受换乘优惠个辰光会得发出“滴滴”声,弗是一般性个“滴”一声;必过轨道交通换乘轨道交通、磁浮线、旅游线、机场线、定制公交、部分社区巴士弗参与优惠。公交换乘轨道交通,基准辰光是轨道交通进站辰光搭仔公共交通阿末一趟刷卡个辰光;轨道交通换乘公交,基准辰光是轨道交通出站辰光搭仔公共交通刷卡个辰光。2022年12月3号开始么,[[随申码]]、乘车码实现对上海公交、地铁、轮渡个全覆盖,也好享受轨道交通帮公交间个优惠<ref>{{cite web|url=https://new.qq.com/rain/a/20221202A08M0J00.html|title=12月3日起,随申码、乘车码实现上海公交、地铁、对江轮渡全面覆盖|author=极目新闻|date=2022-12-02}}</ref>。
* [[上海轨道交通]](参见[[上海地铁车票与票价#优惠]]):每個自然月里向用同一张[[上海公共交通卡]]、同一只Metro大都会账号或同一渠道同一账号个上海公共交通乘车码乘上海地铁实际累积消费满70块,箇只号头里向,满70块个箇笔搭挺下来个消费侪打九折,第二个号头重置。另外,持[[上海公共交通卡]]个乘客来勒虚拟换乘站好来勒30分钟里向出站换乘,里程连续计算。<ref>{{Cite web|url=http://service.shmetro.com/cphc/14.htm|title=地铁优惠情况 - 申通地铁官网|accessdate=2020-08-17|author=申通地铁集团|date=|publisher=|archivedate=2018-05-01|archiveurl=https://web.archive.org/web/20180501111630/http://service.shmetro.com/cphc/14.htm}}</ref>
* [[上海轮渡]]:对非空调摆渡船(上海轮渡已取消非空调轮渡),每個自然月里向,以60趟为一周期,後40趟打8折。乘空调船么,次数累计必过没箇优惠,但是同一天里向乘多埭个,第二埭开始么每趟优惠一块。
* [[上海磁浮示范运营线]]:用公共交通卡乘磁浮列车,普通舱是40块个优惠票价。
* [[P+R|P+R停车换乘]]:勒垃地铁车站个公共换乘停车场(库),每日天5点30分到23点30分里向停车子,而且卡里向当天又勒垃箇站换乘轨道交通个记录,就好享受每趟5-10块个停车收费优惠<ref>{{cite web |title = 上海试点"P+R" 停车换乘轨交享优惠 |publisher = xinhuanet.com |date = 2009-07-20 |url = http://www.xinhuanet.com/chinanews/2009-07/20/content_17140460.htm |accessdate = 2009-07-22 |language = zh |archivedate = 2009-11-07 |archiveurl = https://web.archive.org/web/20091107135418/http://www.xinhuanet.com/chinanews/2009-07/20/content_17140460.htm }}</ref><ref>{{cite web |title = 沪12月起新增4个P+R停车点 收费5-10元/次 |publisher = 东方网 |date = 2010-11-29 |url = http://sh.eastday.com/qtmt/20101129/u1a830305.html |accessdate = 2013-02-10 |language = zh-cn |archivedate = 2016-03-04 |archiveurl = https://web.archive.org/web/20160304195239/http://sh.eastday.com/qtmt/20101129/u1a830305.html }}</ref>。
== 参考 ==
{{Reflist|30em}}
== 外部链接 ==
* [http://www.sptcc.com 上海公共交通卡股份有限公司]{{zh-cn}}
[[Category:上海交通]]
[[Category:上海久事集团]]
[[Category:中国交通智能卡]]
4vdhjwqn508qcjrav507kq2gz4nqab9
模块:Lang
828
53607
398094
366847
2026-08-06T16:33:07Z
Lt2818
23148
398094
Scribunto
text/plain
--[=[
Lua support for the {{lang}}, {{langx}}, {{lang-??}}, and {{transliteration}} templates and replacement of various supporting templates.
]=]
require('strict');
local getArgs = require ('Module:Arguments').getArgs;
local unicode = require ("Module:Unicode data"); -- for is_Latin() and is_rtl()
local yesno = require ('Module:Yesno');
local lang_data = mw.loadData ('Module:Lang/data'); -- language name override and transliteration tool-tip tables
local lang_name_table = lang_data.lang_name_table; -- language codes, names, regions, scripts, suppressed scripts
local lang_table = lang_data.lang_name_table.lang;
local lang_dep_table = lang_data.lang_name_table.lang_dep;
local script_table = lang_data.lang_name_table.script;
local region_table = lang_data.lang_name_table.region;
local variant_table = lang_data.lang_name_table.variant;
local suppressed_table = lang_data.lang_name_table.suppressed;
local override_table = lang_data.override;
local synonym_table = mw.loadData ('Module:Lang/ISO 639 synonyms'); -- ISO 639-2/639-2T code translation to 639-1 code
local cfg = mw.loadData ('Module:Lang/configuration' .. (mw.getCurrentFrame():getTitle():match ('/sandbox') or '')); -- for internationalization
local is_latn_data = mw.loadData ('Module:Lang/data/is latn data');
local sizeof_ranges_t = is_latn_data.sizeof_ranges_t;
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
local content_lang = mw.language.getContentLanguage();
local this_wiki_lang_tag = content_lang.code; -- get this wiki's language tag
local this_wiki_lang_dir = content_lang:getDir(); -- get this wiki's language direction
local initial_style_state; -- set by lang_xx_normal() and lang_xx_italic()
local maint_cats = {}; -- maintenance categories go here
local maint_msgs = {}; -- and their messages go here
--[[--------------------------< M A K E _ E R R O R _ S P A N >--------------------------------------------------
]]
local function make_error_span (template, msg)
return table.concat ({'<span style="color:#d33">', cfg.misc_text_t.error, ': ', template, msg, '</span>'})
end
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
Substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.
]]
local function substitute (message, data_t)
return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end
--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
Assembles an error message from template name, message text, help link, and error category.
]]
local function make_error_msg (msg, args_t, template)
local category;
local text; -- handle the oddity that is {{langx}}
if cfg.templates_t.langxx == template then
text = args_t.text or args_t[1]; -- for {{lang-xx}}
else
text = args_t.text or args_t[2]; -- for {{lang}}, {{langx}}, and {{transliteration}}
end
if cfg.templates_t.transliteration == template then
category = cfg.make_error_msg_t.xlit_err_cat;
else
category = cfg.make_error_msg_t.lang_err_cat;
end
local category_link = ((0 == namespace or 10 == namespace) and not args_t.nocat) and substitute ('[[Category:$1]]', {category}) or '';
return substitute ('[$1] <span style="color:#d33">$2: {{$3}}: $4 ([[:Category:$5|$6]])</span>$7', -- { prevents template name from being treated as a template call in certain situations
{
text or cfg.make_error_msg_t.undefined,
cfg.misc_text_t.error,
template,
msg,
category,
cfg.misc_text_t.help,
category_link
})
end
--[[--------------------------< P A R A M E T E R _ V A L I D A T E >------------------------------------------
]]
local function parameter_validate (args_t, template)
local err_msg = cfg.parameter_validate_t.invalid_param;
if cfg.templates_t.lang == template then -- for {{lang}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_t[param] and -- unique {{lang}} parameters
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langx == template then -- for {{langx}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_langx_t[param] and -- unique {{langx}} parameters
not cfg.known_params_t.params_x_t[param] and -- common to {{langx}} and {{lang-xx}}
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langxx == template then -- for {{lang-xx}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_xx_t[param] and -- unique {{lang-xx}} parameters
not cfg.known_params_t.params_x_t[param] and -- common to {{langx}} and {{lang-xx}}
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
end
end
--[[--------------------------< 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
--[[--------------------------< I N V E R T _ I T A L I C S >-------------------------------------------------
This function attempts to invert the italic markup a args.text by adding/removing leading/trailing italic markup
in args.text. Like |italic=unset, |italic=invert disables automatic italic markup. Individual leading/trailing
apostrophes are converted to their HTML numeric entity equivalent so that the new italic markup doesn't become
bold markup inadvertently.
Leading and trailing wiki markup is extracted from args.text into separate table elements. Addition, removal,
replacement of wiki markup is handled by a string.gsub() replacement table operating only on these separate elements.
In the string.gsub() matching pattern, '.*' matches empty string as well as the three expected wiki markup patterns.
This function expects that markup in args.text is complete and correct; if it is not, oddness may result.
]]
local function invert_italics (source)
local invert_pattern_table = { -- leading/trailing markup add/remove/replace patterns
[""]="\'\'", -- empty string becomes italic markup
["\'\'"]="", -- italic markup becomes empty string
["\'\'\'"]="\'\'\'\'\'", -- bold becomes bold italic
["\'\'\'\'\'"]="\'\'\'", -- bold italic become bold
};
local seg = {};
source = source:gsub ("%f[\']\'%f[^\']", '''); -- protect single quote marks from being interpreted as bold markup
seg[1] = source:match ('^(\'\'+%f[^\']).+') or ''; -- get leading markup, if any; ignore single quote
seg[3] = source:match ('.+(%f[\']\'\'+)$') or ''; -- get trailing markup, if any; ignore single quote
if '' ~= seg[1] and '' ~= seg[3] then -- extract the 'text'
seg[2] = source:match ('^\'\'+%f[^\'](.+)%f[\']\'\'+$') -- from between leading and trailing markup
elseif '' ~= seg[1] then
seg[2] = source:match ('^\'\'+%f[^\'](.+)') -- following leading markup
elseif '' ~= seg[3] then
seg[2] = source:match ('(.+)%f[\']\'\'+$') -- preceding trailing markup
else
seg[2] = source -- when there is no markup
end
seg[1] = invert_pattern_table[seg[1]] or seg[1]; -- replace leading markup according to pattern table
seg[3] = invert_pattern_table[seg[3]] or seg[3]; -- replace leading markup according to pattern table
return table.concat (seg); -- put it all back together and done
end
--[[--------------------------< V A L I D A T E _ I T A L I C >------------------------------------------------
Validates |italic= or |italics= assigned values.
When |italic= is set and has an acceptable assigned value, return the matching CSS font-style property value or,
for the special case 'default', return nil.
When |italic= is not set, or has an unacceptable assigned value, return nil and a nil error message.
When both |italic= and |italics= are set, returns nil and a 'conflicting' error message.
The return value nil causes the calling lang, lang_xx, or xlit function to set args.italic according to the template's
defined default ('inherit' for {{lang}}, 'inherit' or 'italic' for {{lang-??}} depending on
the individual template's requirements, 'italic' for {{transliteration}}) or to the value appropriate to |script=, if set ({{lang}}
and {{lang-??}} only).
Accepted values and the values that this function returns are are:
nil - when |italic= absent or not set; returns nil
default - for completeness, should rarely if ever be used; returns nil
yes - force args.text to be rendered in italic font; returns 'italic'
no - force args.text to be rendered in normal font; returns 'normal'
unset - disables font control so that font-style applied to text is dictated by markup inside or outside the template; returns 'inherit'
invert - disables font control so that font-style applied to text is dictated by markup outside or inverted inside the template; returns 'invert'
]]
local function validate_italic (args)
local properties = {[cfg.keywords_t.affirmative] = 'italic', [cfg.keywords_t.negative] = 'normal', [cfg.keywords_t.unset] = 'inherit', [cfg.keywords_t.invert] = 'invert', [cfg.keywords_t.default] = nil};
local count = 0
for _, arg in pairs {'italic', 'italics', 'i'} do
if args[arg] then
count = count + 1
end
end
if count > 1 then -- return nil and an error message if more than one is set
return nil, cfg.validate_italic_t.multi_italic;
end
return properties[args.italic or args.italics or args.i], nil; -- return an appropriate value and a nil error message
end
--[=[--------------------------< V A L I D A T E _ C A T _ A R G S >----------------------------------------------------------
Default behavior of the {{lang}} and {{lang-??}} templates is to add categorization when the templates are used in main space.
This default functionality may be suppressed by setting |nocat=yes or |cat=no. This function selects one of these two parameters
to control categorization.
Because having two parameters with 'opposite' names and 'opposite' values is confusing, this function accepts only affirmative
values for |nocat= and only negative values for |cat=; in both cases the 'other' sense (and non-sense) is not accepted and the
parameter is treated as if it were not set in the template.
Sets args.nocat to true if categorization is to be turned off; to nil if the default behavior should apply.
Accepted values for |nocat= are the text strings:
'yes', 'y', 'true', 't', on, '1' -- [[Module:Yesno]] returns logical true for all of these; false or nil else
for |cat=
'no', 'n', 'false', 'f', 'off', '0' -- [[Module:Yesno]] returns logical false for all of these; true or nil else
]=]
local function validate_cat_args (args)
if not (args.nocat or args.cat) then -- both are nil, so categorize
return;
end
if false == yesno (args.cat) or true == yesno (args.nocat) then
args.nocat = true; -- set to true when args.nocat is affirmative; nil else (as if the parameter were not set in the template)
else -- args.nocat is the parameter actually used.
args.nocat = 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
private: lower case prefixed with -x-
]]
local function format_ietf_tag (code, script, region, variant, private)
local out = {};
if is_set (private) then
return table.concat ({code:lower(), 'x', private:lower()}, '-'); -- if private, all other tags ignored
end
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 >--------------------------------------------------
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; only one variant subtag supported
private subtag - x- followed by 1-8 alnum private code; only supported with the primary language tag
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
lang-x-private
each of lang, script, region, variant, and private, when used, must be valid.
Languages with both two- and three-character code synonyms are promoted to the two-character synonym because
the IANA registry file omits the synonymous three-character code; we cannot depend on browsers understanding
the synonymous three-character codes in the lang= attribute.
For {{lang-??}} templates, the parameters |script=, |region=, and |variant= are supported (not supported in {{lang}}
because those parameters are superfluous to the IETF subtags in |code=).
Returns six values; all lower case. Valid parts are returned as themselves; omitted parts are returned as empty strings, invalid
parts are returned as nil; the sixth returned item is an error message (if an error detected) or nil.
See http://www.rfc-editor.org/rfc/bcp/bcp47.txt section 2.1.
]]
local function get_ietf_parts (source, args_script, args_region, args_variant)
local code, script, region, variant, private; -- IETF tag parts
if not is_set (source) then
return nil, nil, nil, nil, nil, cfg.get_ietf_parts_t.missing_lang_tag;
end
local pattern = { -- table of tables holding acceptable IETF tag patterns and short names of the IETF part captured by the pattern
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 1 - ll-Ssss-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 2 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 3 - ll-Ssss-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 4 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d%d)$', 's', 'v'}, -- 5 - ll-Ssss-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'v'}, -- 6 - ll-Ssss-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a)%-(%d%d%d%d)$', 'r', 'v'}, -- 7 - ll-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%d%d%d)%-(%d%d%d%d)$', 'r', 'v'}, -- 8 - ll-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 9 - ll-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 10 - ll-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%d%d%d%d)$', 'v'}, -- 11 - ll-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%w%w%w%w%w%w?%w?%w?)$', 'v'}, -- 12 - ll-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)$', 's', 'r'}, -- 13 - ll-Ssss-RR
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)$', 's', 'r'}, -- 14 - ll-Ssss-DDD (region is 3 digits)
{'^(%a%a%a?)%-(%a%a%a%a)$', 's'}, -- 15 - ll-Ssss
{'^(%a%a%a?)%-(%a%a)$', 'r'}, -- 16 - ll-RR
{'^(%a%a%a?)%-(%d%d%d)$', 'r'}, -- 17 - ll-DDD (region is 3 digits)
{'^(%a%a%a?)$'}, -- 18 - ll
{'^(%a%a%a?)%-x%-(%w%w?%w?%w?%w?%w?%w?%w?)$', 'p'}, -- 19 - ll-x-pppppppp (private is 1-8 alnum characters)
}
local t = {}; -- table of captures; serves as a translator between captured IETF tag parts and named variables
for i, v in ipairs (pattern) do -- spin through the pattern table looking for a match
local c1, c2, c3, c4; -- captures in the 'pattern' from the pattern table go here
c1, c2, c3, c4 = source:match (pattern[i][1]); -- one or more captures set if source matches pattern[i])
if c1 then -- c1 always set on match
code = c1; -- first capture is always code
t = {
[pattern[i][2] or 'x'] = c2, -- fill the table of captures with the rest of the captures
[pattern[i][3] or 'x'] = c3, -- take index names from pattern table and assign sequential captures
[pattern[i][4] or 'x'] = c4, -- index name may be nil in pattern[i] table so "or 'x'" spoofs a name for this index in this table
};
script = t.s or ''; -- translate table contents to named variables;
region = t.r or ''; -- absent table entries are nil so set named IETF parts to empty string for concatenation
variant= t.v or '';
private = t.p or '';
break; -- and done
end
end
if not code then
return nil, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_tag, {source}); -- 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 (override_table[code] or lang_table[code] or synonym_table[code] or lang_dep_table[code]) then
return nil, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_code, {code}); -- invalid language code, don't know about the others (don't care?)
end
if synonym_table[code] then -- if 639-2/639-2T code has a 639-1 synonym
table.insert (maint_cats, substitute (cfg.get_ietf_parts_t.maint_promo_cat, {code}));
table.insert (maint_msgs, substitute (cfg.get_ietf_parts_t.maint_promo_msg, {code, synonym_table[code]}));
code = synonym_table[code]; -- use the synonym
end
if is_set (script) then
if is_set (args_script) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_scr; -- both code with script and |script= not allowed
end
else
script = args_script or ''; -- use args.script if provided
end
if is_set (script) then
script = script:lower(); -- ensure that we use and return lower case version of this
if not script_table[script] then
return code, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_scr_code, {script, code}); -- language code OK, invalid script, don't know about the others (don't care?)
end
end
if suppressed_table[script] then -- ensure that code-script does not use a suppressed script
if in_array (code, suppressed_table[script]) then
return code, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.script_code, {script, code}); -- language code OK, script is suppressed for this code
end
end
if is_set (region) then
if is_set (args_region) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_reg; -- both code with region and |region= not allowed
end
else
region = args_region or ''; -- use args.region if provided
end
if is_set (region) then
region = region:lower(); -- ensure that we use and return lower case version of this
if not region_table[region] then
return code, script, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_reg_code, {region, code});
end
end
if is_set (variant) then
if is_set (args_variant) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_var; -- both code with variant and |variant= not allowed
end
else
variant = args_variant or ''; -- use args.variant if provided
end
if is_set (variant) then
variant = variant:lower(); -- ensure that we use and return lower case version of this
if not variant_table[variant] then -- make sure variant is valid
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var, {variant});
end -- does this duplicate/replace tests in lang() and lang_xx()?
if is_set (script) then -- if script set it must be part of the 'prefix'
if not in_array (table.concat ({code, '-', script}), variant_table[variant]['prefixes']) then
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code_scr, {variant, code, script});
end
elseif is_set (region) then -- if region set, there are some prefixes that require lang code and region (en-CA-newfound)
if not in_array (code, variant_table[variant]['prefixes']) then -- first see if lang code is all that's required (en-oxendict though en-GB-oxendict is preferred)
if not in_array (table.concat ({code, '-', region}), variant_table[variant]['prefixes']) then -- now try for lang code and region (en-CA-newfound)
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code_reg, {variant, code, region});
end
end
else -- cheap way to determine if there are prefixes; fonipa and others don't have prefixes; # operator always returns 0
if variant_table[variant]['prefixes'][1] and not in_array (code, variant_table[variant]['prefixes']) then
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code, {variant, code});
end
end
end
if is_set (private) then
private = private:lower(); -- ensure that we use and return lower case version of this
if not override_table[table.concat ({code, '-x-', private})] then -- make sure private tag is valid; note that index
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_pri, {private});
end
end
return code, script, region, variant, private, nil; -- return the good bits; make sure that msg is nil
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
--[[--------------------------< D I V _ M A R K U P _ A D D >--------------------------------------------------
Adds <i> and </i> tags to list-item text or to implied <p>..</p> text. Mixed not supported.
]]
local function div_markup_add (text, style)
if text:find ('^\n[%*:;#]') then -- look for list markup; list markup must begin at start of text
if 'italic' == style then
return text:gsub ('(\n[%*:;#]+)([^\n]+)', '%1<i>%2</i>'); -- insert italic markup at each list item
else
return text;
end
end
if text:find ('\n+') then -- look for any number of \n characters in text
text = text:gsub ('([^\n])\n([^\n])', '%1 %2'); -- replace single newline characters with a space character which mimics MediaWiki
if 'italic' == style then
text = text:gsub('[^\n]+', '<p><i>%1</i></p>'); -- insert p and italic markup tags at each implied p (two or more consecutive '\n\n' sequences)
else
text = text:gsub ('[^\n]+', '<p>%1</p>'); -- insert p markup at each implied p
text = text:gsub ('\n', ''); -- strip newline characters
end
end
return text;
end
--[[--------------------------< T I T L E _ W R A P P E R _ M A K E >------------------------------------------
Makes a <span title="<title text>"><content_text></span> or <div title="<title text>"><content_text></div> where
<title text> is in the tool-tip in the wiki's local language and <content_text> is non-local-language text in
HTML markup. This because the lang= attribute applies to the content of its enclosing tag.
<tag> holds a string 'div' or 'span' used to choose the correct wrapping tag.
]]
local function title_wrapper_make (title_text, content_text, tag)
local wrapper_t = {};
table.insert (wrapper_t, table.concat ({'<', tag})); -- open opening wrapper tag
table.insert (wrapper_t, ' title=\"'); -- begin title attribute
table.insert (wrapper_t, title_text); -- add <title_text>
table.insert (wrapper_t, '\">'); -- end title attribute and close opening wrapper tag
table.insert (wrapper_t, content_text); -- add <content_text>
table.insert (wrapper_t, table.concat ({'</', tag, '>'})); -- add closing wrapper tag
return table.concat (wrapper_t); -- make a big string and done
end
--[[--------------------------< M A K E _ T E X T _ H T M L >--------------------------------------------------
Add the HTML markup to text according to the type of content that it is: <span> or <i> tags for inline content or
<div> tags for block content
The lang= attribute also applies to the content of the tag where it is placed so this is wrong because 'Spanish
language text' is English:
<i lang="es" title="Spanish language text">casa</i>
should be:
<span title="Spanish language text"><i lang="es">casa</i></span>
or for <div>...</div>:
<div title="Spanish language text"><div lang="es"><spanish-language-text></div></div>
]]
local function make_text_html (code, text, tag, rtl, style, size, language)
local html_t = {};
local style_added = '';
local wrapper_tag = tag; -- <tag> gets modified so save a copy for use when/if we create a wrapper span or div
if text:match ('^%*') then
table.insert (html_t, '*'); -- move proto language text prefix outside of italic markup if any; use numeric entity because plain splat confuses MediaWiki
text = text:gsub ('^%*', ''); -- remove the splat from the text
end
if 'span' == tag then -- default HTML tag for inline content
if 'italic' == style then -- but if italic
tag = 'i'; -- change to <i> tags
end
else -- must be div so go
text = div_markup_add (text, style); -- handle implied <p>, implied <p> with <i>, and list markup (*;:#) with <i>
end
table.insert (html_t, table.concat ({'<', tag})); -- open the <i>, <span>, or <div> HTML tag
code = code:gsub ('%-x%-.*', ''); -- strip private use subtag from code tag because meaningless outside of Wikipedia
table.insert (html_t, table.concat ({' lang="', code, '\"'})); -- add language attribute
if (rtl or unicode.is_rtl(text)) and ('ltr' == this_wiki_lang_dir) then -- text is right-to-left on a left-to-right wiki
table.insert (html_t, ' dir="rtl"'); -- add direction attribute for right-to-left languages
elseif not (rtl or unicode.is_rtl(text)) and ('rtl' == this_wiki_lang_dir) then -- text is left-to-right on a right-to-left wiki
table.insert (html_t, ' dir="ltr"'); -- add direction attribute for left-to-right languages
end
if 'normal' == style then -- when |italic=no
table.insert (html_t, ' style=\"font-style: normal;'); -- override external markup, if any
style_added = '\"'; -- remember that style attribute added and is not yet closed
end
if is_set (size) then -- when |size=<something>
if is_set (style_added) then
table.insert (html_t, table.concat ({' font-size: ', size, ';'})); -- add when style attribute already inserted
else
table.insert (html_t, table.concat ({' style=\"font-size: ', size, ';'})); -- create style attribute
style_added = '\"'; -- remember that style attribute added and is not yet closed
end
end
table.insert (html_t, table.concat ({style_added, '>'})); -- close the opening HTML tag
table.insert (html_t, text); -- insert the text
table.insert (html_t, table.concat ({'</', tag, '>'})); -- close the 'text' <i>, <span>, or <div> HTML tag
if is_set (language) then -- create a <title_text> string for the title= attribute in a wrapper span or div
local title_text;
if 'zxx' == code then -- special case for this tag 'no linguistic content'
title_text = substitute ('$1 $2', {language, cfg.make_text_html_t.zxx}); -- not a language so don't use 'language' in title text
elseif mw.ustring.find (language, 'languages', 1, true) then
title_text = substitute ('$1 $2', {language, cfg.make_text_html_t.collective}); -- for collective languages
else
title_text = substitute ('$1-$2', {language, cfg.make_text_html_t.individual}); -- for individual languages
end
return title_wrapper_make (title_text, table.concat (html_t), wrapper_tag);
else
return table.concat (html_t);
end
end
--[=[-------------------------< M A K E _ C A T E G O R Y >----------------------------------------------------
For individual language, <language>, returns:
[[Category:Articles containing <language>-language text]]
For English:
[[Category:Articles containing explicitly cited English-language text]]
For ISO 639-2 collective languages (and for 639-1 bh):
[[Category:Articles with text in <language> languages]]
]=]
local function make_category (code, language_name, nocat, name_get)
if ((0 ~= namespace) or nocat) and not name_get then -- only categorize in article space
return ''; -- return empty string for concatenation
end
if mw.ustring.find (language_name, 'languages', 1, true) then
return substitute ('[[$1 $2]]', {cfg.make_category_t.collective_cat, language_name});
end
if this_wiki_lang_tag == code then
return substitute ('[[$1 $2 $3-$4]]', { -- unique category name for the local language
cfg.make_category_t.cat_prefix,
cfg.make_category_t.explicit_cat,
language_name,
cfg.make_category_t.cat_postfix,
});
else
return substitute ('[[$1 $2-$3]]', { -- category for individual languages
cfg.make_category_t.cat_prefix,
language_name,
cfg.make_category_t.cat_postfix,
});
end
end
--[[--------------------------< M A K E _ T R A N S L I T >----------------------------------------------------
Return translit <i lang=xx-Latn>...</i> where xx is the language code; else return empty string.
The value |script= is not used in {{transliteration}} for this purpose; instead it uses |code. Because language scripts
are listed in the {{transliteration}} 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).
This function is used by both lang_xx() and xlit()
lang_xx() always provides code, language_name, and translit; may provide tscript; never provides style
xlit() always provides language_name, translit, and one of code or tscript, never both; always provides style
For {{transliteration}}, style only applies when a language code is provided.
]]
local function make_translit (code, language_name, translit, std, tscript, style, engvar)
local title_t = lang_data.translit_title_table; -- table of transliteration standards and the language codes and scripts that apply to those standards
local title_text = ''; -- tool tip text for title= attribute
std = std and std:lower(); -- lower case for table indexing
if not is_set (std) and not is_set (tscript) then -- when neither standard nor script specified
title_text = language_name; -- write a generic tool tip
if not mw.ustring.find (language_name, 'languages', 1, true) then -- collective language names (plural 'languages' is part of the name)
title_text = substitute ('$1-$2', {title_text, cfg.misc_text_t.language}); -- skip this text (individual and macro languages only)
end
title_text = substitute ('$1 $2', {title_text, mw.ustring.lower (cfg.engvar_t[engvar]['romanisz_lc'])}); -- finish the tool tip; use romanization when neither script nor standard supplied
elseif is_set (std) and is_set (tscript) then -- when both are specified
if title_t[std] then -- and if standard is legitimate
if title_t[std][tscript] then -- and if script for that standard is legitimate
if script_table[tscript] then
title_text = substitute ('$1$2 ($3 $4) $5', { -- add the appropriate text to the tool tip
title_text,
title_t[std][tscript:lower()],
script_table[tscript],
cfg.make_translit_t.script,
cfg.make_translit_t.transliteration,
});
else
title_text = title_text .. title_t[std]['default']; -- use the default if script not in std table; TODO: maint cat? error message because script not found for this standard?
end
else
title_text = title_text .. title_t[std]['default']; -- use the default if script not in std table; TODO: maint cat? error message because script not found for this standard?
end
else
return ''; -- invalid standard, setup for error message
end
elseif is_set (std) then -- translit-script not set, use language code
if not title_t[std] then return ''; end -- invalid standard, setup for error message
if title_t[std][code] then -- if language code is in the table (xlit may not provide a language code)
title_text = substitute ('$1$2 ($3 $4) $5', { -- add the appropriate text to the tool tip
title_text,
title_t[std][code:lower()],
language_name,
cfg.misc_text_t.language,
cfg.make_translit_t.transliteration,
});
else -- code doesn't match
title_text = title_text .. title_t[std]['default']; -- so use the standard's default
end
else -- here if translit-script set but translit-std not set
if title_t['no_std'][tscript] then
title_text = title_text .. title_t['no_std'][tscript]; -- use translit-script if set
elseif title_t['no_std'][code] then
title_text = title_text .. title_t['no_std'][code]; -- use language code
else
if is_set (tscript) then
title_text = substitute ('$1$2-$3 $4', { -- write a script tool tip
title_text,
language_name,
cfg.make_translit_t.script,
cfg.make_translit_t.transliteration,
});
elseif is_set (code) then
if not mw.ustring.find (language_name, 'languages', 1, true) then -- collective language names (plural 'languages' is part of the name)
title_text = substitute ('$1-$2', { -- skip this text (individual and macro languages only)
title_text,
cfg.misc_text_t.language,
});
end
title_text = substitute ('$1 $2', { -- finish the tool tip
title_text,
cfg.make_translit_t.transliteration,
});
else
title_text = substitute ('$1 $2', { -- generic tool tip (can we ever get here?)
title_text,
cfg.make_translit_t.transliteration,
});
end
end
end
local tag
if is_set (code) then -- when a language code is provided (always with {{lang-??}} templates, not always with {{transliteration}})
code = code:match ('^(%a%a%a?)'); -- strip all subtags leaving only the language subtag
if not style then -- nil for the default italic style
tag = '<i lang="%s-Latn">%s</i>'
else
tag = '<span style="font-style: %s" lang="%s-Latn">%s</span>' -- non-standard style, construct a span tag for it
tag = string.format(tag, style, "%s", "%s")
end
tag = string.format(tag, code, "%s")
else
tag = '<span>%s</span>' -- when no language code: no lang= attribute, not italic ({{transliteration}} only)
end
tag = string.format(tag, translit) -- add the translit text
if '' == title_text then -- when there is no need for a tool-tip
return tag; -- done
else
title_text = cfg.engvar_sel_t.gb == engvar and title_text:gsub ('([Rr]omani)z', '%1s') or title_text; -- gb eng when engvar specifies gb eng; us eng else
return title_wrapper_make (title_text, tag, 'span'); -- wrap with a tool-tip span and done
end
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''''' unless |italic=unset or |italic=invert.
]]
local function validate_text (template, args)
if not is_set (args.text) then
return make_error_msg (cfg.validate_text_t.no_text, args, template);
end
if args.text:find ("%f[\']\'\'\'\'%f[^\']") or args.text:find ("\'\'\'\'\'[\']+") then -- because we're looking, look for 4 appostrophes or 6+ appostrophes
return make_error_msg (cfg.validate_text_t.malformed_markup, args, template);
end
local style = args.italic;
if (cfg.keywords_t.unset ~= style) and (cfg.keywords_t.invert ~=style) then
if args.text:find ("%f[\']\'\'%f[^\']") or args.text:find ("%f[\']\'\'\'\'\'%f[^\']") then -- italic but not bold, or bold italic
return make_error_msg (cfg.validate_text_t.italic_markup, args, template);
end
end
end
--[[--------------------------< R E N D E R _ M A I N T >------------------------------------------------------
Render mainenance messages and categories.
]]
local function render_maint (nocat)
local maint = {};
if 0 < #maint_msgs then -- when there are maintenance messages
table.insert (maint, table.concat ({'<span class="lang-comment" style="font-style: normal; display: none; color: #33aa33; margin-left: 0.3em;">'})); -- opening <span> tag
for _, msg in ipairs (maint_msgs) do
table.insert (maint, table.concat ({msg, ' '})); -- add message strings
end
table.insert (maint, '</span>'); -- close the span
end
if (0 < #maint_cats) and (0 == namespace) and not nocat then -- when there are maintenance categories; article namespace only
for _, cat in ipairs (maint_cats) do
table.insert (maint, table.concat ({'[[Category:', cat, ']]'})); -- format and add the categories
end
end
return table.concat (maint);
end
--[[--------------------------< P R O T O _ P R E F I X >------------------------------------------------------
For proto languages, text is prefixed with a splat. We do that here as a flag for make_text_html() so that a splat
will be rendered outside of italic markup (if used). If the first character in text here is already a splat, we
do nothing.
proto_param is boolean or nil; true adds splat prefix regardless of language name; false removes and inhibits
regardless of language name; nil does nothing; presumes that the value in text is correct but removes extra splac.
]]
local function proto_prefix (text, language_name, proto_param)
if false == proto_param then -- when forced by |proto=no
return text:gsub ('^%**', ''); -- return text without splat prefix regardless of language name or existing splat prefix in text
elseif (language_name:find ('^Proto%-') or (true == proto_param)) then -- language is a proto or forced by |proto=yes
return text:gsub ('^%**', '*'); -- prefix proto-language text with a splat; also removes duplicate prefixing splats
end
return text:gsub ('^%*+', '*'); -- return text unmolested except multiple splats reduced to one splat
end
--[[--------------------------< H A S _ P O E M _ T A G >------------------------------------------------------
Looks for a poem strip marker in text; returns true when found; false else.
Auto-italic detection disabled when text has poem stripmarker because it is not possible for this code to know
the content that will replace the stripmarker.
]]
local function has_poem_tag (text)
return text:find ('\127[^\127]*UNIQ%-%-poem%-[%a%d]+%-QINU[^\127]*\127') and true or false;
end
--[[--------------------------< H T M L _ T A G _ S E L E C T >------------------------------------------------
Inspects content of and selectively trims text. Returns text and the name of an appropriate HTML tag for text.
If text contains:
\n\n text has implied <p>..</p> tags - trim leading and trailing whitespace and return
If text begins with list markup:
\n* unordered
\n; definition
\n: definition
\n# ordered
trim all leading whitespace except \n and trim all trailing whitespace
If text contains <poem>...</poem> stripmarker, return text unmodified and choose <div>..</div> tags because
the stripmarker is replaced with text wrapped in <div>..</div> tags.
If the text contains any actual <div>...</div> tags, then it's again returned unmodified and <div>...</div>
tags are used to wrap it, to prevent div/span inversion.
]]
local function html_tag_select (text)
local tag;
if has_poem_tag (text) then -- contains poem stripmarker (we can't know the content of that)
tag = 'div'; -- poem replacement is in div tags so lang must use div tags
elseif text:find ('<div') then -- reductive; if the text contains a div tag, we must use div tags
tag = 'div';
elseif mw.text.trim (text):find ('\n\n+') then -- contains implied p tags
text = mw.text.trim (text); -- trim leading and trailing whitespace characters
tag = 'div'; -- must be div because span may not contain p tags (added later by MediaWiki); poem replacement is in div tags
elseif text:find ('\n[%*:;%#]') then -- if text has list markup
text = text:gsub ('^[\t\r\f ]*', ''):gsub ('%s*$', ''); -- trim all whitespace except leading newline character '\n'
tag = 'div'; -- must be div because span may not contain ul, dd, dl, ol tags (added later by MediaWiki)
else
text = mw.text.trim (text); -- plain text
tag = 'span'; -- so span is fine
end
return text, tag;
end
--[[--------------------------< V A L I D A T E _ P R O T O >--------------------------------------------------
Validates value assigned to |proto=; permitted values are yes and no; yes returns as true, no returns as false,
empty string (or parameter omitted) returns as nil; any other value returns nil with <proto_param> as second
return value for use in error message.
]]
local function validate_proto (proto_param)
if cfg.keywords_t.affirmative == proto_param then
return true;
elseif cfg.keywords_t.negative == proto_param then
return false;
elseif is_set (proto_param) then
return nil, proto_param; -- |proto= something other than 'yes' or 'no'
else
return nil; -- missing or empty
end
end
--[[--------------------------< L A N G U A G E _ N A M E _ G E T >--------------------------------------------
Common function to return language name from the data set according to IETF tag.
Returns language name if found in data tables; nil else.
]]
local function language_name_get (ietf, code, cat)
ietf = ietf:lower(); -- ietf:lower() because format_ietf_tag() returns mixed case
local name; -- remains nil if not found
if override_table[ietf] then -- look for whole IETF tag in override table
name = override_table[ietf];
elseif override_table[code] then -- not there so try basic language tag
name = override_table[code];
elseif lang_table[code] then -- shift to IANA active tag/name table
name = lang_table[code];
elseif lang_dep_table[code] then -- try the IANA deprecated tag/name table
name = lang_dep_table[code];
end
return name; -- name from data tables or nil
end
--[[--------------------------< T E X T _ S C R I P T _ M A T C H _ T E S T >----------------------------------
IETF script subtag should match the script of the <text>. This module does not attempt to know all scripts and
what they look like. It does know what Latn script looks like so when <text> is written using other than the Latn
script, the IETF script subtag, if present, should not be Latn.
Conversely, when <text> is written using the Latn script, the IETF script subtag, if present, should be Latn.
For the purposes of this test, Latf (Fraktur) and Latg (Gaelic) are considered to be equivalent to Latn because
unicode treats these two scripts as font-specific variants of Latn.
Returns an error message when mismatch detected; nil else.
]]
local function text_script_match_test (script, is_latn_text, pos, char)
local scripts_t = {['latf'] = true, ['latg'] = true, ['latn'] = true}; -- unicode 'latn' scripts; 'latf' and 'latg' are font variants so there are no Fraktur or Gaelic codepoints
if is_set (script) then -- don't bother with the rest of this if <script> is nil or empty string
script = script:lower(); -- lower case to index into <scripts_t>
if is_latn_text then -- when text is wholly Latn script
if not scripts_t[script] then -- but a non-Latn script is specified
return cfg.text_script_match_test_t.latn_txt_mismatch; -- emit an error message
end
else -- when text is not wholly Latn script
if scripts_t[script] then -- but a Latn script is specified
return substitute (cfg.text_script_match_test_t.latn_scr_mismatch, {pos, char}); -- emit an error message with position of first offending character
end
end
end
end
--[[--------------------------< B I N A R Y _ S E A R C H >---------------------------------------------------
conducts a binary search of <ranges_t> for a sub-range that holds <target>.
returns boolean true if a sub-range holding <target> is found; boolean false else.
]]
local function binary_search (target, ranges_t)
local idx_bot = 1; -- initialize to index of first key
local idx_top = sizeof_ranges_t; -- initialize to index of last key (number of keys)
if (target < ranges_t[idx_bot][1]) or (target > ranges_t[idx_top][2]) then -- invalid; target out of range
return; -- abandon
end
local idx_mid; -- calculated index of range midway between top index and bottom index
local flag = false; -- flag to tell us when we've evaluated last (highest) range in <ranges_t>
while 1 do
idx_mid = math.ceil ((idx_bot + idx_top) / 2); -- get the mid-point in the <ranges_t> sequence
if (target >= ranges_t[idx_mid][1]) and (target <= ranges_t[idx_mid][2]) then -- indexed range low value <= target <= indexed range high value
return true; -- we found the range that holds the <target> character; return true
elseif (target > ranges_t[idx_mid][2]) then -- is <target> > indexed range high value?
idx_bot = idx_mid; -- adjust <idx_bot> up
else -- here when <target> less than indexed range low value
idx_top = idx_mid - 1; -- adjust <idx_top> down
end
if flag then
break; -- here when we just evaluated the last range and <target> not found
end
if not flag and (idx_bot == idx_top) then -- set true just before we evaluate the last (highest) range in <ranges_t>
flag = true;
end
end
end
--[[--------------------------< I S _ L A T I N >--------------------------------------------------------------
compare <text> as codepoints to lists of known codepoints accepted as Latn script
returns boolean true and modified <text> when <text> is wrapped in accept-as-written markup
returns boolean true and <text> when codepoint is known
returns boolean false, <text>, non-Latn codepoint position in <text> (left to right), and the codepoint character
when codepoint is not known
TODO: when text has accept-as-written markup, return a non-boolean value to indicate that <text> is not wholly
latn script? Use that return value to create non-Latn HTML lang= attribute because <text> isn't really
latn so lang=und (undetermined)? or instead, omit the -Latn subtag? (without -Latn need to force |italic=yes)
]]
local function is_latin (text, tag)
local count;
text, count = text:gsub ('^%(%((.+)%)%)$', '%1'); -- remove accept-as-written markup if present
if 0 ~= count then
return true, text; -- markup present so assume that <text> is Latn-script
end
local pos = 0; -- position counter for error messaging
for codepoint in mw.ustring.gcodepoint (text) do -- fetch each code point
pos = pos + 1; -- bump the position counter
if not is_latn_data.singles_t[codepoint] and -- codepoint not found in the singles list?
not binary_search (codepoint, is_latn_data.ranges_t) and -- codepoint not a member of a listed range?
not (tag and is_latn_data.specials_t[codepoint] and is_latn_data.specials_t[codepoint][tag]) then -- not a language-specific codepoint?
return false, text, pos, mw.ustring.char (codepoint); -- codepoint not known; return false with codepoint position and character representation
end
end
return true, text; -- is known; return <text>
end
--[[--------------------------< _ L A N G >--------------------------------------------------------------------
Entry point for {{lang}}.
There should be no reason to set parameters in the {{lang}} {{#invoke:}}
<includeonly>{{#invoke:lang|lang}}</includeonly>
Parameters are received from the template's frame (parent frame).
]]
local function _lang (args)
local out = {};
local language_name; -- used to make category names
local category_name; -- same as language_name except that it retains any parenthetical disambiguators (if any) from the data set
local subtags = {}; -- IETF subtags script, region, variant, and private
local code; -- the language code
local msg; -- for error messages
local tag = 'span'; -- initial value for make_text_html()
local template = args.template or cfg.templates_t.lang;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
validate_cat_args (args); -- determine if categorization should be suppressed
if args[1] and args.code then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {'1', cfg.lang_t.conflict_n_param_types.code}), args, template);
else
args.code = args[1] or args.code; -- prefer args.code
end
if args[2] and args.text then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {'2', cfg.lang_t.conflict_n_param_types.text}), args, template);
else
args.text = args[2] or args.text; -- prefer args.text
end
msg = validate_text (template, args); -- ensure that |text= is set
if is_set (msg) then -- msg is an already-formatted error message
return msg;
end
args.text, tag = html_tag_select (args.text); -- inspects text; returns appropriate HTML tag with text trimmed accordingly
args.rtl = args.rtl == cfg.keywords_t.affirmative; -- convert to boolean: 'yes' -> true, other values -> false
args.proto, msg = validate_proto (args.proto); -- return boolean, or nil, or nil and error message flag
if msg then
return make_error_msg (substitute (cfg.lang_t.invalid_proto, {msg}), args, template);
end
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code); -- |script=, |region=, |variant= not supported because they should be part of args.code ({{{1}}} in {{lang}})
if msg then
return make_error_msg (msg, args, template);
end
local is_latn_text, pos, char;
is_latn_text, args.text, pos, char= is_latin (args.text, code); -- make a boolean
msg = text_script_match_test (subtags.script, is_latn_text, pos, char)
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if nil == args.italic then -- nil when |italic= absent or not set or |italic=default; args.italic controls
args.italic = 'inherit'; -- italic not set; inherit current style
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
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles
language_name = language_name_get (args.code, code, true); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
if cfg.keywords_t.invert == args.italic and 'span' == tag then -- invert only supported for in-line content
args.text = invert_italics (args.text)
end
args.text = proto_prefix (args.text, language_name, args.proto); -- prefix proto-language text with a splat
table.insert (out, make_text_html (args.code, args.text, tag, args.rtl, args.italic, args.size, language_name));
table.insert (out, render_maint (args.nocat)); -- maintenance messages and categories
return table.concat (out); -- put it all together and done
end
--[[--------------------------< L A N G >----------------------------------------------------------------------
Entry point for {{lang}}.
There should be no reason to set parameters in the {{lang}} {{#invoke:}}
<includeonly>{{#invoke:lang|lang}}</includeonly>
Parameters are received from the template's frame (parent frame).
]]
local function lang (frame)
local args_t = getArgs (frame, { -- this code so that we can detect and handle wiki list markup in text
valueFunc = function (key, value)
if 2 == key or 'text' == key then -- the 'text' parameter; do not trim wite space
return value; -- return untrimmed 'text'
elseif value then -- all other values: if the value is not nil
value = mw.text.trim (value); -- trim whitespace
if '' ~= value then -- empty string when value was only whitespace
return value;
end
end
return nil; -- value was empty or contained only whitespace
end -- end of valueFunc
});
args_t.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang|...}}
local msg = parameter_validate (args_t, cfg.templates_t.lang); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args_t, cfg.templates_t.lang); -- when template has unsupported params, abandon with error message
end
return _lang (args_t);
end
--[[--------------------------< T R A N S L A T I O N _ M A K E >----------------------------------------------
Stand-alone function to create literal translation of main text.
Also used by {{lang-x2}}.
]]
local function translation_make (args_t)
local translation_t = {', '}; -- initialize output
if 'none' ~= args_t.label then -- if we want a label
table.insert (translation_t, '<small>'); -- open the <small> HTML tag
if cfg.keywords_t.negative == args_t.link then
table.insert (translation_t, substitute ('<abbr title="$1">$2</abbr>', {cfg.translation_make_t.lit_xlation, cfg.translation_make_t.lit_abbr})); -- unlinked form
else
table.insert (translation_t, make_wikilink (cfg.translation_make_t.lit_xlation, cfg.translation_make_t.lit_abbr)); -- linked form
end
table.insert (translation_t, " </small>"); -- close the <small> HTML tag
end
table.insert (translation_t, table.concat ({''', args_t.translation, '''})); -- use HTML entities to avoid wiki markup confusion
return table.concat (translation_t); -- make a big string and done
end
--[[--------------------------< _ L A N G _ X X >--------------------------------------------------------------
For the {{lang-??}} templates, the only parameter required to be set in the template is the language code. All
other parameters can, usually should, be written in the template call. For {{lang-??}} templates for languages
that can have multiple writing systems, it may be appropriate to set |script= as well.
For each {{lang-??}} template choose the appropriate entry-point function so that this function knows the default
styling that should be applied to text.
For normal, upright style:
<includeonly>{{#invoke:lang|lang_xx_inherit|code=xx}}</includeonly>
For italic style:
<includeonly>{{#invoke:lang|lang_xx_italic|code=xx}}</includeonly>
All other parameters should be received from the template's frame (parent frame)
Supported parameters are:
|code = (required) the IANA language code
|script = IANA script code; especially for use with languages that use multiple writing systems
|region = IANA region code
|variant = IANA variant code
|text = (required) the displayed text in language specified by code
|link = boolean false ('no') does not link code-spcified language name to associated language article
|rtl = boolean true ('yes') identifies the language specified by code as a right-to-left language
|nocat = boolean true ('yes') inhibits normal categorization; error categories are not affected
|cat = boolian false ('no') opposite form of |nocat=
|italic = boolean true ('yes') renders displayed text in italic font; boolean false ('no') renders displayed text in normal font; not set renders according to initial_style_state
|lit = text that is a literal translation of text
|label = 'none' to suppress all labeling (language name, 'translit.', 'lit.')
any other text replaces language-name label - automatic wikilinking disabled
for those {{lang-??}} templates that support transliteration (those templates where |text= is not entirely latn script):
|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-??}}, the positional parameters are:
{{{1}}} text
{{{2}}} transliterated text
{{{3}}} literal translation text
no other positional parameters are allowed
]]
local function _lang_xx (args, base_template) -- base_template will be either of 'langx' or 'lang-xx'
local out = {};
local language_name; -- used to make display text, article links
local category_name; -- same as language_name except that it retains any parenthetical disambiguators (if any) from the data set
local subtags = {}; -- IETF subtags script, region, and variant
local code; -- the language code
local translit_script_name; -- name associated with IANA (ISO 15924) script code
local translit;
local msg; -- for error messages
local tag = 'span'; -- initial value for make_text_html()
local template = args.template or base_template;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
local text_idx = (cfg.templates_t.langx == base_template) and 2 or 1; -- for {{langx}} 'text' positional parameter is '2'
local translit_idx = (cfg.templates_t.langx == base_template) and 3 or 2;
local xlate_idx = (cfg.templates_t.langx == base_template) and 4 or 3;
if args[text_idx] and args.text then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {translit_idx, cfg.lang_t.conflict_n_param_types.text}), args, template);
else
args.text = args[text_idx] or args.text; -- prefer positional 'text' parameter
end
msg = validate_text (template, 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
args.text, tag = html_tag_select (args.text); -- inspects text; returns appropriate HTML tag with text trimmed accordingly
if args[translit_idx] and args.translit then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {translit_idx, cfg.lang_t.conflict_n_param_types.translit}), args, template);
else
args.translit = args[translit_idx] or args.translit -- prefer positional 'translit' parameter
end
args.engvar = cfg.default_engvar;
if args[xlate_idx] and (args.translation or args.lit) then
return make_error_msg (substitute (cfg.lang_xx_t.conflict_n_lit, {translit_idx}), args, template);
elseif args.translation and args.lit then
return make_error_msg (cfg.lang_xx_t.conflict_lit, args, template);
else
args.translation = args[xlate_idx] or args.translation or args.lit; -- prefer positional 'translation' parameter
end
if args.links and args.link then
return make_error_msg (cfg.lang_xx_t.conflict_link, args, template);
else
args.link = args.link or args.links; -- prefer args.link
end
validate_cat_args (args); -- determine if categorization should be suppressed
args.rtl = args.rtl == cfg.keywords_t.affirmative; -- convert to boolean: 'yes' -> true, other values -> false
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code, args.script, args.region, args.variant); -- private omitted because private
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
if args.translit then
local latn, pos, char;
latn, args.translit, pos, char = is_latin (args.translit, (('' ~= subtags.private) and (code .. '-x-' .. subtags.private)) or code);
if not latn then
return make_error_msg (substitute (cfg.lang_xx_t.translit_nonlatn, {pos, char}), args, template);
end
end
local is_latn_text, text, pos, char = is_latin (args.text, code); -- make a boolean
args.text = text; -- may have been modified (accept-as-written markup removed)
msg = text_script_match_test (subtags.script, is_latn_text, pos, char)
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if cfg.templates_t.langx == base_template then -- auto-italics for {{langx}} templates; adapted from {{lang}} (no support for poem tag)
if nil == args.italic then -- nil when |italic= absent or not set or |italic=default; args.italic controls
if ('latn' == subtags.script) or -- script is latn
(this_wiki_lang_tag ~= code and not is_set (subtags.script) and is_latn_text) then -- text is not this wiki's language, no script specified and is wholly latn script (auto-italics)
args.italic = 'italic'; -- set font-style:italic
else
args.italic = 'inherit'; -- italic not set; script not latn; inherit current style
end
end
else -- {{lang-xx}} does not do auto italics; retained for those wikis that don't support {{langx}}
if nil == args.italic then -- args.italic controls
if is_set (subtags.script) then
if 'latn' == subtags.script then
args.italic = 'italic'; -- |script=Latn; set for font-style:italic
else
args.italic = initial_style_state; -- italic not set; script is not latn; set for font-style:<initial_style_state>
end
else
args.italic = initial_style_state; -- here when |italic= and |script= not set; set for font-style:<initial_style_state>
end
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
args.proto, msg = validate_proto (args.proto); -- return boolean, or nil, or nil and error message flag
if msg then
return make_error_msg (substitute (cfg.lang_t.invalid_proto, {args.proto}), args, template);
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles
language_name = language_name_get (args.code, code, true); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
category_name = language_name; -- category names retain IANA parenthetical diambiguators (if any)
language_name = language_name:gsub ('%s+%b()', ''); -- remove IANA parenthetical disambiguators or qualifiers from names that have them
if args.label then
if 'none' ~= args.label then
table.insert (out, table.concat ({args.label, ':'})); -- custom label
end
else
if cfg.keywords_t.negative == args.link then
table.insert (out, language_name); -- language name without wikilink
else
if mw.ustring.find (language_name, 'languages', 1, true) then
table.insert (out, make_wikilink (language_name)); -- collective language name uses simple wikilink
elseif lang_data.article_name[args.code:lower()] then -- is IETF tag in article name over ride?
table.insert (out, make_wikilink (lang_data.article_name[args.code:lower()], language_name)); -- language name with wikilink from override data
elseif lang_data.article_name[code] then -- is language tag in article override
table.insert (out, make_wikilink (lang_data.article_name[code], language_name)); -- language name with wikilink from override data
else
table.insert (out, make_wikilink (language_name)); -- language name with wikilink
end
end
table.insert (out, ':'); -- separator
end
if cfg.keywords_t.invert == args.italic then
args.text = invert_italics (args.text)
end
args.text = proto_prefix (args.text, language_name, args.proto); -- prefix proto-language text with a splat
table.insert (out, make_text_html (args.code, args.text, tag, args.rtl, args.italic, args.size, ('none' == args.label) and language_name or nil))
if is_set (args.translit) and not is_latn_text then -- transliteration; not supported when args.text is wholly latn text (this is an imperfect test)
table.insert (out, ','); -- comma to separate text from translit
if 'none' ~= args.label then
table.insert (out, '<small>');
if script_table[args['translit-script']] then -- when |translit-script= is set, try to use the script's name
translit_script_name = script_table[args['translit-script']];
else
translit_script_name = language_name; -- fall back on language name
end
local translit_title_obj = mw.title.makeTitle (0, substitute ('$1 $2',{cfg.lang_xx_t.romanization, translit_script_name})); -- make a title object; no engvar, article titles use US spelling
if translit_title_obj.exists and (cfg.keywords_t.negative ~= args.link) then
table.insert (out, make_wikilink (substitute ('$1 $2', {cfg.lang_xx_t.romanization, translit_script_name or language_name}),
substitute ('$1', {cfg.engvar_t[args.engvar]['romanisz_pt']})) .. ':'); -- make a wikilink if there is an article to link to; engvar the display text
else
table.insert (out, substitute ('$1:', {cfg.engvar_t[args.engvar]['romanisz_pt']})); -- else plain text per engvar
end
table.insert (out, '</small>'); -- close the small tag
end
translit = make_translit (args.code, language_name, args.translit, args['translit-std'], args['translit-script'], nil, args.engvar)
if is_set (translit) then
table.insert (out, translit);
else
return make_error_msg (substitute ('$1: $2', {cfg.lang_xx_t.invalid_xlit_std, args['translit-std'] or '[missing]'}), args, template);
end
elseif is_set (args.translit) and is_latn_text then -- when creating a transliteration of Latn script <text>
return make_error_msg (cfg.lang_xx_t.xlit_of_latn, args, template); -- emit error message and abandon
end
if is_set (args.translation) then -- translation (not supported in {{lang}})
table.insert (out, translation_make (args));
end
table.insert (out, render_maint(args.nocat)); -- maintenance messages and categories
return table.concat (out); -- put it all together and done
end
--[[--------------------------< L A N G _ X X _ A R G S _ G E T >----------------------------------------------
Common function to get args table from {{lang-??}} templates.
Returns table of args.
Text positional parameters are not trimmed here but are selectively trimmed at html_tag_select().
]]
local function lang_xx_args_get (frame, base_template)
local args_t = getArgs(frame,
{
parentFirst= true, -- parameters in the template override parameters set in the {{#invoke:}}
valueFunc = function (key, value)
if ((cfg.templates_t.langx == base_template) and 2 or 1) == key then -- the 'text' positional parameter; 1 for {{lang-??}}, 2 for {{langx}}; do not trim wite space
return value; -- return untrimmed 'text' positional parameter
elseif value then -- all other values: if the value is not nil
value = mw.text.trim (value); -- trim whitespace
if '' ~= value then -- empty string when value was only whitespace
return value;
end
end
return nil; -- value was empty or contained only whitespace
end -- end of valueFunc
});
return args_t;
end
--[[--------------------------< L A N G _ X X _ I T A L I C >--------------------------------------------------
Entry point for those {{lang-??}} templates that call lang_xx_italic(). Sets the initial style state to italic.
]]
local function lang_xx_italic (frame)
local args = lang_xx_args_get (frame, cfg.templates_t.langxx);
args.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang_xx_italic|...}}
local msg = parameter_validate (args, cfg.templates_t.langxx); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args, cfg.templates_t.langxx); -- when template has unsupported params, abandon with error message
end
initial_style_state = 'italic';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G _ X X _ I T A L I C >------------------------------------------------
Entry point from another module. Sets the initial style state to italic.
]]
local function _lang_xx_italic (args)
initial_style_state = 'italic';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< L A N G _ X X _ I N H E R I T >------------------------------------------------
Entry point for those {{lang-??}} templates that call lang_xx_inherit(). Sets the initial style state to inherit.
]]
local function lang_xx_inherit (frame)
local args = lang_xx_args_get (frame, cfg.templates_t.langxx);
args.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang_xx_inherit|...}}
local msg = parameter_validate (args, cfg.templates_t.langxx); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args, cfg.templates_t.langxx); -- when template has unsupported params, abandon with error message
end
initial_style_state = 'inherit';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G _ X X _ I N H E R I T >----------------------------------------------
Entry point from another module. Sets the initial style state to inherit.
]]
local function _lang_xx_inherit (args)
initial_style_state = 'inherit';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G X >------------------------------------------------------------------
Entry point from another module.
]]
local function _langx (args_t)
local langx_data = mw.loadData ('Module:Lang/langx'); -- get necessary data
local rtl_t = langx_data.rtl_t; -- get list of language tags for languages that are rendered right-to-left
local link_t = langx_data.link_t; -- get list of language tags for {{lang-??}} templates that set |link=<something>
local size_t = langx_data.size_t; -- get list of language tags for {{lang-??}} templates that set |size=<something>
local msg = parameter_validate (args_t, cfg.templates_t.langx);
if msg then
return make_error_msg (msg, args_t, cfg.templates_t.langx);
end
args_t.code = args_t[1] or args_t.code; -- get the language tag; must be {{{1}}} or |code=
if not args_t.code then
return make_error_msg (cfg.get_ietf_parts_t.missing_lang_tag, args_t, cfg.templates_t.langx);
end
args_t.rtl = args_t.rtl or (rtl_t[args_t.code] and cfg.keywords_t.affirmative); -- prefer |rtl= in template call, use rtl_t else
args_t.link = args_t.link or link_t[args_t.code]; -- prefer |link= in template call, use link_t felse
args_t.size = args_t.size or size_t[args_t.code]; -- prefer |size= in template call, use size_t else
args_t[1] = nil; -- unset to mimic {{lang-??}} templates which set |code=xx
local lang_subtag = args_t.code; -- use only the base language subtag for unsupported tag test; some args_t.code are modified by |script= etc
return _lang_xx (args_t, cfg.templates_t.langx);
end
--[[--------------------------< L A N G X >--------------------------------------------------------------------
Entry point for {{langx}}.
this function calls _lang_xx() to render non-English text. The {{lang-??}} templates have three positional paramters
but {{langx}} has four:
| 1 | 2 | 3 | 4
{{lang-xx |<text> |<xlit> |<xlat> }}
{{langx |<tag> |<text> |<xlit> |<xlat> }}
The calls to lang_xx_args_get() and _lang_xx() use 'langx' as a flag for those functions to select the proper
positional parameters.
{{lang-??}} depends on the calling template to select 'inherit' or 'italic' to establish the default rendering.
{{langx}} can't do that. The initial version of {{langx}} relied on a list of language tags (inherit_t in ~/langx)
scraped from those {{lang-??}} templates that call lang_xx_inherit() to render text in upright font. langx() now
uses auto-italics code adapted from {{lang}} (doesn't support poem tags).
]]
local function langx (frame)
local args_t = lang_xx_args_get (frame, cfg.templates_t.langx); -- get the arguments; 'langx' is the <base_template> used to decide which positional param is 'text', 'translit', 'lit'
return _langx (args_t);
end
--[[--------------------------< _ I S _ I E T F _ T A G >------------------------------------------------------
Returns true when a language name associated with IETF language tag exists; nil else. IETF language tag must be valid.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Module entry point from another module.
]]
local function _is_ietf_tag (tag) -- entry point when this module is require()d into another
local c, s, r, v, p, err; -- code, script, region, variant, private, error message
c, s, r, v, p, err = get_ietf_parts (tag); -- disassemble tag into constituent part and validate
return ((c and not err) and true) or nil; -- return true when code portion has a value without error message; nil else
end
--[[--------------------------< I S _ I E T F _ T A G >--------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function is_ietf_tag (frame)
return _is_ietf_tag (getArgs (frame)[1]); -- args[1] is the IETF language tag to be tested; also get parent frame
end
--[[--------------------------< I S _ I E T F _ T A G _ F R A M E >--------------------------------------------
Module entry point from an {{#invoke:}}; same as is_ietf_tag() except does not get parameters from the parent
(template) frame. This function not useful when called by {{lang|fn=is_ietf_tag_frame|<tag>}} because <tag>
is in the parent frame.
]]
local function is_ietf_tag_frame (frame)
return _is_ietf_tag (getArgs (frame, {frameOnly = true,})[1]); -- args[1] is the IETF language tag to be tested; do not get parent frame
end
--[[--------------------------< _ N A M E _ F R O M _ T A G >--------------------------------------------------
Returns language name associated with IETF language tag if valid; error message else.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Set invoke's |link= parameter to yes to get wikilinked version of the language name.
Module entry point from another module.
]]
local function _name_from_tag (args)
local subtags = {}; -- IETF subtags script, region, variant, and private
local raw_code = args[1]; -- save a copy of the input IETF subtag
local link = cfg.keywords_t.affirmative == args['link']; -- make a boolean
local label = args.label;
local code; -- the language code
local msg; -- gets an error message if IETF language tag is malformed or invalid
local language_name = '';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (raw_code);
if msg then
local template = (args['template'] and table.concat ({'{{', args['template'], '}}: '})) or ''; -- make template name (if provided by the template)
return make_error_span (template, msg);
end
raw_code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles; private omitted because private
language_name = language_name_get (raw_code, code); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
if 'yes' ~= args.raw then
language_name = language_name:gsub ('%s+%b()', ''); -- remove IANA parenthetical disambiguators or qualifiers from names that have them
end
if link then -- when |link=yes, wikilink the language name
if mw.ustring.find (language_name, 'languages', 1, true) then
language_name = make_wikilink (language_name, label); -- collective language name uses simple wikilink
elseif lang_data.article_name[raw_code:lower()] then -- is IETF tag in article name override?
language_name = make_wikilink (lang_data.article_name[raw_code:lower()], label or language_name); -- language name with wikilink from override data
elseif lang_data.article_name[code] then -- is language tag in article name override?
language_name = make_wikilink (lang_data.article_name[code], label or language_name); -- language name with wikilink from override data
else
language_name = make_wikilink (substitute ('$1 $2', {language_name, cfg.misc_text_t.language}), label or language_name); -- language name with wikilink
end
end
return language_name;
end
--[[--------------------------< N A M E _ F R O M _ T A G >----------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function name_from_tag (frame) -- entry point from an {{#invoke:lang|name_from_tag|<IETF tag>|link=<yes>|template=<template name>}}
return _name_from_tag (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame
end
--[[--------------------------< _ T A G _ F R O M _ N A M E >--------------------------------------------------
Returns the IETF language tag associated with the language name. Spelling of language name must be correct
according to the spelling in the source tables. When a standard language name has a parenthetical disambiguator,
that disambiguator must be omitted (they are not present in the data name-to-tag tables).
Module entry point from another module.
]]
local function _tag_from_name (args) -- entry point from another module
local msg;
if args[1] and '' ~= args[1] then
local data = mw.loadData ('Module:Lang/tag from name'); -- get the reversed data tables TODO: change when going live
local lang = args[1]:lower(); -- allow any-case for the language name (speeling must till be correct)
local tag = data.rev_override_table[lang] or data.rev_lang_table[lang] or data.rev_lang_dep_table[lang]; -- get the code; look first in the override then in the standard
if tag then
return tag, true; -- language name found so return tag and done; second return used by is_lang_name()
else
msg = substitute (cfg.tag_from_name_t.lang_not_found, {args[1]}); -- language name not found, error message
end
else
msg = cfg.tag_from_name_t.missing_lang_name; -- language name not found, error message
end
local template = '';
if args.template and '' ~= args.template then
template = table.concat ({'{{', args['template'], '}}: '}); -- make template name (if provided by the template)
end
return make_error_span (template, msg);
end
--[[--------------------------< T A G _ F R O M _ N A M E >----------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function tag_from_name (frame) -- entry point from an {{#invoke:lang|tag_from_name|<language name>|link=<yes>|template=<template name>}}
local result, _ = _tag_from_name (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame; supress second return used by is_lang_name()
return result;
end
--[[--------------------------< I S _ L A N G _ N A M E >------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function is_lang_name (frame)
local _, result = _tag_from_name (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame; supress second return used by tag_from_name()
return result and true or nil;
end
--[[--------------------------< _ X L I T >--------------------------------------------------------------------
Module entry point from another module.
]]
local function _xlit (args)
local title_table = lang_data.translit_title_table; -- table of transliteration standards and the language codes and scripts that apply to those standards
local language_name; -- language name that matches language code; used for tool tip
local translit; -- transliterated text to display
local script; -- IANA script
local msg; -- for when called functions return an error message
local template = args.template or cfg.templates_t.transliteration;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
if is_set (args[3]) then -- [3] set when {{transliteration|code|standard|text}}
args.text = args[3]; -- get the transliterated text
args.translit_std = args[2] and args[2]:lower(); -- get the standard; lower case for table indexing
if not title_table[args.translit_std] then
return make_error_msg (substitute (cfg.transl_t.unrecog_xlit_std, {args.translit_std}), args, template);
end
else
if is_set (args[2]) then -- [2] set when {{transliteration|code|text}}
args.text = args[2]; -- get the transliterated text
else
if args[1] and (args[1]:match ('^%a%a%a?%a?$') or -- args[2] missing; is args[1] a language or script tag or is it the transliterated text?
args[1]:match ('^%a%a%a?%-x%-')) then -- or is args[1] a private-use tag
return make_error_msg (cfg.transl_t.no_text, args, template); -- args[1] is a code so we're missing text
else
args.text = args[1]; -- args[1] is not a code so we're missing that; assign args.text for error message
return make_error_msg (cfg.transl_t.missing_lang_scr, args, template);
end
end
end
if is_set (args[1]) then -- IANA language code used for HTML lang= attribute; or ISO 15924 script code
if args[1]:match ('^%a%a%a?%a?$') or args[1]:match ('^%a%a%a?%-x%-') then -- args[1] has correct form?
args.code = args[1]:lower(); -- use the language/script code; only (2, 3, or 4 alpha characters) or private-use; lower case because table indexes are lower case
else
return make_error_msg (substitute (cfg.transl_t.unrecog_lang_scr, {args[1]}), args, template); -- invalid language / script code
end
else
return make_error_msg (cfg.transl_t.missing_lang_scr, args, template); -- missing language / script code so quit
end
local is_latn_text, pos, char;
is_latn_text, args.text, pos, char= is_latin (args.text, args.code); -- is latn text? strip accept-as-written markup
if not is_latn_text then -- when text is not latn
return make_error_msg (substitute (cfg.lang_xx_t.translit_nonlatn, {pos, char}), args, template); -- abandon with error message
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if 'italic' == args.italic then -- 'italic' when |italic=yes; because that is same as absent or not set and |italic=default
args.italic = nil; -- set to nil;
end
args.engvar = cfg.default_engvar;
if override_table[args.code] then -- is code a language code defined in the override table?
language_name = override_table[args.code];
args.code = args.code:match ('^%a%a%a?'); -- if private use, strip all but language subtag
elseif lang_table[args.code] then -- is code a language code defined in the standard language code tables?
language_name = lang_table[args.code];
elseif lang_dep_table[args.code] then -- is code a language code defined in the deprecated language code tables?
language_name = lang_dep_table[args.code];
elseif script_table[args.code] then -- if here, code is not a language code; is it a script code?
language_name = script_table[args.code];
script = args.code; -- code was an ISO 15924 script so use that instead
args.code = ''; -- unset because not a language code
else
return make_error_msg (substitute (cfg.transl_t.unrecog_lang_scr, {args.code}), args, template); -- invalid language / script code
end
-- here only when all parameters passed to make_translit() are valid
return make_translit (args.code, language_name, args.text, args.translit_std, script, args.italic, args.engvar);
end
--[[--------------------------< X L I T >----------------------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function xlit (frame)
return _xlit (getArgs(frame));
end
--[[--------------------------< C A T E G O R Y _ F R O M _ T A G >--------------------------------------------
Returns category name associated with IETF language tag if valid; error message else.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Module entry point from another module.
]]
local function _category_from_tag (args_t)
local subtags = {}; -- IETF subtags script, region, variant, and private
local raw_code = args_t[1]; -- save a copy of the input IETF subtag
local link = cfg.keywords_t.affirmative == args_t.link; -- make a boolean
local label = args_t.label;
local code; -- the language code
local msg; -- gets an error message if IETF language tag is malformed or invalid
local category_name = '';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (raw_code);
if msg then
local template = (args_t.template and table.concat ({'{{', args_t.template, '}}: '})) or ''; -- make template name (if provided by the template)
return make_error_span (template, msg);
end
raw_code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles; private omitted because private
category_name = language_name_get (raw_code, code); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
category_name = make_category (code, category_name, nil, true):gsub ('[%[%]]', '');
if link then
return table.concat ({'[[:', category_name, ']]'});
else
return category_name;
end
end
--[[--------------------------< C A T E G O R Y _ F R O M _ T A G >--------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function category_from_tag (frame) -- entry point from an {{#invoke:lang|category_from_tag|<IETF tag>|template=<template name>}}
return _category_from_tag (getArgs (frame)); -- pass-on the args table, nothing else; getArgs() so we also get parent frame
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {
category_from_tag = category_from_tag, -- frame entry points when this module is #invoke:ed into templates/wikitext
lang = lang, -- entry point for {{lang}}
langx = langx, -- entry point for {{langx}}
lang_xx_inherit = lang_xx_inherit, -- entry points for {{lang-??}}
lang_xx_italic = lang_xx_italic,
is_ietf_tag = is_ietf_tag,
is_ietf_tag_frame = is_ietf_tag_frame,
is_lang_name = is_lang_name,
tag_from_name = tag_from_name, -- returns IETF tag associated with language name
name_from_tag = name_from_tag, -- used for template documentation; possible use in ISO 639 name from code templates
xlit = xlit, -- entry point for {{transliteration}}
_category_from_tag = _category_from_tag, -- API entry points when this module is require()d into other modules
_lang = _lang,
_langx = _langx,
_lang_xx_inherit = _lang_xx_inherit,
_lang_xx_italic = _lang_xx_italic,
_is_ietf_tag = _is_ietf_tag,
get_ietf_parts = get_ietf_parts,
_tag_from_name = _tag_from_name,
_name_from_tag = _name_from_tag,
_xlit = _xlit,
_translation_make = translation_make,
};
80wjy302x2t1fsamzx9jt54nvjeuiuh
398095
398094
2026-08-06T16:43:28Z
Lt2818
23148
398095
Scribunto
text/plain
--[=[
Lua support for the {{lang}}, {{langx}}, {{lang-??}}, and {{transliteration}} templates and replacement of various supporting templates.
]=]
require('strict');
local getArgs = require ('Module:Arguments').getArgs;
local unicode = require ("Module:Unicode data"); -- for is_Latin() and is_rtl()
local yesno = require ('Module:Yesno');
local lang_data = mw.loadData ('Module:Lang/data'); -- language name override and transliteration tool-tip tables
local lang_name_table = lang_data.lang_name_table; -- language codes, names, regions, scripts, suppressed scripts
local lang_table = lang_data.lang_name_table.lang;
local lang_dep_table = lang_data.lang_name_table.lang_dep;
local script_table = lang_data.lang_name_table.script;
local region_table = lang_data.lang_name_table.region;
local variant_table = lang_data.lang_name_table.variant;
local suppressed_table = lang_data.lang_name_table.suppressed;
local override_table = lang_data.override;
local synonym_table = mw.loadData ('Module:Lang/ISO 639 synonyms'); -- ISO 639-2/639-2T code translation to 639-1 code
local cfg = mw.loadData ('Module:Lang/configuration' .. (mw.getCurrentFrame():getTitle():match ('/sandbox') or '')); -- for internationalization
local is_latn_data = mw.loadData ('Module:Lang/data/is latn data');
local sizeof_ranges_t = is_latn_data.sizeof_ranges_t;
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
local content_lang = mw.language.getContentLanguage();
local this_wiki_lang_tag = content_lang.code; -- get this wiki's language tag
local this_wiki_lang_dir = content_lang:getDir(); -- get this wiki's language direction
local initial_style_state; -- set by lang_xx_normal() and lang_xx_italic()
local maint_cats = {}; -- maintenance categories go here
local maint_msgs = {}; -- and their messages go here
--[[--------------------------< M A K E _ E R R O R _ S P A N >--------------------------------------------------
]]
local function make_error_span (template, msg)
return table.concat ({'<span style="color:#d33">', cfg.misc_text_t.error, ': ', template, msg, '</span>'})
end
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
Substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.
]]
local function substitute (message, data_t)
return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end
--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
Assembles an error message from template name, message text, help link, and error category.
]]
local function make_error_msg (msg, args_t, template)
local category;
local text; -- handle the oddity that is {{langx}}
if cfg.templates_t.langxx == template then
text = args_t.text or args_t[1]; -- for {{lang-xx}}
else
text = args_t.text or args_t[2]; -- for {{lang}}, {{langx}}, and {{transliteration}}
end
if cfg.templates_t.transliteration == template then
category = cfg.make_error_msg_t.xlit_err_cat;
else
category = cfg.make_error_msg_t.lang_err_cat;
end
local category_link = ((0 == namespace or 10 == namespace) and not args_t.nocat) and substitute ('[[Category:$1]]', {category}) or '';
return substitute ('[$1] <span style="color:#d33">$2: {{$3}}: $4 ([[:Category:$5|$6]])</span>$7', -- { prevents template name from being treated as a template call in certain situations
{
text or cfg.make_error_msg_t.undefined,
cfg.misc_text_t.error,
template,
msg,
category,
cfg.misc_text_t.help,
category_link
})
end
--[[--------------------------< P A R A M E T E R _ V A L I D A T E >------------------------------------------
]]
local function parameter_validate (args_t, template)
local err_msg = cfg.parameter_validate_t.invalid_param;
if cfg.templates_t.lang == template then -- for {{lang}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_t[param] and -- unique {{lang}} parameters
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langx == template then -- for {{langx}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_langx_t[param] and -- unique {{langx}} parameters
not cfg.known_params_t.params_x_t[param] and -- common to {{langx}} and {{lang-xx}}
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langxx == template then -- for {{lang-xx}}
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_xx_t[param] and -- unique {{lang-xx}} parameters
not cfg.known_params_t.params_x_t[param] and -- common to {{langx}} and {{lang-xx}}
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
end
end
--[[--------------------------< 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
--[[--------------------------< I N V E R T _ I T A L I C S >-------------------------------------------------
This function attempts to invert the italic markup a args.text by adding/removing leading/trailing italic markup
in args.text. Like |italic=unset, |italic=invert disables automatic italic markup. Individual leading/trailing
apostrophes are converted to their HTML numeric entity equivalent so that the new italic markup doesn't become
bold markup inadvertently.
Leading and trailing wiki markup is extracted from args.text into separate table elements. Addition, removal,
replacement of wiki markup is handled by a string.gsub() replacement table operating only on these separate elements.
In the string.gsub() matching pattern, '.*' matches empty string as well as the three expected wiki markup patterns.
This function expects that markup in args.text is complete and correct; if it is not, oddness may result.
]]
local function invert_italics (source)
local invert_pattern_table = { -- leading/trailing markup add/remove/replace patterns
[""]="\'\'", -- empty string becomes italic markup
["\'\'"]="", -- italic markup becomes empty string
["\'\'\'"]="\'\'\'\'\'", -- bold becomes bold italic
["\'\'\'\'\'"]="\'\'\'", -- bold italic become bold
};
local seg = {};
source = source:gsub ("%f[\']\'%f[^\']", '''); -- protect single quote marks from being interpreted as bold markup
seg[1] = source:match ('^(\'\'+%f[^\']).+') or ''; -- get leading markup, if any; ignore single quote
seg[3] = source:match ('.+(%f[\']\'\'+)$') or ''; -- get trailing markup, if any; ignore single quote
if '' ~= seg[1] and '' ~= seg[3] then -- extract the 'text'
seg[2] = source:match ('^\'\'+%f[^\'](.+)%f[\']\'\'+$') -- from between leading and trailing markup
elseif '' ~= seg[1] then
seg[2] = source:match ('^\'\'+%f[^\'](.+)') -- following leading markup
elseif '' ~= seg[3] then
seg[2] = source:match ('(.+)%f[\']\'\'+$') -- preceding trailing markup
else
seg[2] = source -- when there is no markup
end
seg[1] = invert_pattern_table[seg[1]] or seg[1]; -- replace leading markup according to pattern table
seg[3] = invert_pattern_table[seg[3]] or seg[3]; -- replace leading markup according to pattern table
return table.concat (seg); -- put it all back together and done
end
--[[--------------------------< V A L I D A T E _ I T A L I C >------------------------------------------------
Validates |italic= or |italics= assigned values.
When |italic= is set and has an acceptable assigned value, return the matching CSS font-style property value or,
for the special case 'default', return nil.
When |italic= is not set, or has an unacceptable assigned value, return nil and a nil error message.
When both |italic= and |italics= are set, returns nil and a 'conflicting' error message.
The return value nil causes the calling lang, lang_xx, or xlit function to set args.italic according to the template's
defined default ('inherit' for {{lang}}, 'inherit' or 'italic' for {{lang-??}} depending on
the individual template's requirements, 'italic' for {{transliteration}}) or to the value appropriate to |script=, if set ({{lang}}
and {{lang-??}} only).
Accepted values and the values that this function returns are are:
nil - when |italic= absent or not set; returns nil
default - for completeness, should rarely if ever be used; returns nil
yes - force args.text to be rendered in italic font; returns 'italic'
no - force args.text to be rendered in normal font; returns 'normal'
unset - disables font control so that font-style applied to text is dictated by markup inside or outside the template; returns 'inherit'
invert - disables font control so that font-style applied to text is dictated by markup outside or inverted inside the template; returns 'invert'
]]
local function validate_italic (args)
local properties = {[cfg.keywords_t.affirmative] = 'italic', [cfg.keywords_t.negative] = 'normal', [cfg.keywords_t.unset] = 'inherit', [cfg.keywords_t.invert] = 'invert', [cfg.keywords_t.default] = nil};
local count = 0
for _, arg in pairs {'italic', 'italics', 'i'} do
if args[arg] then
count = count + 1
end
end
if count > 1 then -- return nil and an error message if more than one is set
return nil, cfg.validate_italic_t.multi_italic;
end
return properties[args.italic or args.italics or args.i], nil; -- return an appropriate value and a nil error message
end
--[=[--------------------------< V A L I D A T E _ C A T _ A R G S >----------------------------------------------------------
Default behavior of the {{lang}} and {{lang-??}} templates is to add categorization when the templates are used in main space.
This default functionality may be suppressed by setting |nocat=yes or |cat=no. This function selects one of these two parameters
to control categorization.
Because having two parameters with 'opposite' names and 'opposite' values is confusing, this function accepts only affirmative
values for |nocat= and only negative values for |cat=; in both cases the 'other' sense (and non-sense) is not accepted and the
parameter is treated as if it were not set in the template.
Sets args.nocat to true if categorization is to be turned off; to nil if the default behavior should apply.
Accepted values for |nocat= are the text strings:
'yes', 'y', 'true', 't', on, '1' -- [[Module:Yesno]] returns logical true for all of these; false or nil else
for |cat=
'no', 'n', 'false', 'f', 'off', '0' -- [[Module:Yesno]] returns logical false for all of these; true or nil else
]=]
local function validate_cat_args (args)
if not (args.nocat or args.cat) then -- both are nil, so categorize
return;
end
if false == yesno (args.cat) or true == yesno (args.nocat) then
args.nocat = true; -- set to true when args.nocat is affirmative; nil else (as if the parameter were not set in the template)
else -- args.nocat is the parameter actually used.
args.nocat = 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
private: lower case prefixed with -x-
]]
local function format_ietf_tag (code, script, region, variant, private)
local out = {};
if is_set (private) then
return table.concat ({code:lower(), 'x', private:lower()}, '-'); -- if private, all other tags ignored
end
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 >--------------------------------------------------
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; only one variant subtag supported
private subtag - x- followed by 1-8 alnum private code; only supported with the primary language tag
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
lang-x-private
each of lang, script, region, variant, and private, when used, must be valid.
Languages with both two- and three-character code synonyms are promoted to the two-character synonym because
the IANA registry file omits the synonymous three-character code; we cannot depend on browsers understanding
the synonymous three-character codes in the lang= attribute.
For {{lang-??}} templates, the parameters |script=, |region=, and |variant= are supported (not supported in {{lang}}
because those parameters are superfluous to the IETF subtags in |code=).
Returns six values; all lower case. Valid parts are returned as themselves; omitted parts are returned as empty strings, invalid
parts are returned as nil; the sixth returned item is an error message (if an error detected) or nil.
See http://www.rfc-editor.org/rfc/bcp/bcp47.txt section 2.1.
]]
local function get_ietf_parts (source, args_script, args_region, args_variant)
local code, script, region, variant, private; -- IETF tag parts
if not is_set (source) then
return nil, nil, nil, nil, nil, cfg.get_ietf_parts_t.missing_lang_tag;
end
local pattern = { -- table of tables holding acceptable IETF tag patterns and short names of the IETF part captured by the pattern
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 1 - ll-Ssss-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 2 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 3 - ll-Ssss-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 4 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d%d)$', 's', 'v'}, -- 5 - ll-Ssss-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'v'}, -- 6 - ll-Ssss-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a)%-(%d%d%d%d)$', 'r', 'v'}, -- 7 - ll-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%d%d%d)%-(%d%d%d%d)$', 'r', 'v'}, -- 8 - ll-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 9 - ll-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 10 - ll-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%d%d%d%d)$', 'v'}, -- 11 - ll-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%w%w%w%w%w%w?%w?%w?)$', 'v'}, -- 12 - ll-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)$', 's', 'r'}, -- 13 - ll-Ssss-RR
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)$', 's', 'r'}, -- 14 - ll-Ssss-DDD (region is 3 digits)
{'^(%a%a%a?)%-(%a%a%a%a)$', 's'}, -- 15 - ll-Ssss
{'^(%a%a%a?)%-(%a%a)$', 'r'}, -- 16 - ll-RR
{'^(%a%a%a?)%-(%d%d%d)$', 'r'}, -- 17 - ll-DDD (region is 3 digits)
{'^(%a%a%a?)$'}, -- 18 - ll
{'^(%a%a%a?)%-x%-(%w%w?%w?%w?%w?%w?%w?%w?)$', 'p'}, -- 19 - ll-x-pppppppp (private is 1-8 alnum characters)
}
local t = {}; -- table of captures; serves as a translator between captured IETF tag parts and named variables
for i, v in ipairs (pattern) do -- spin through the pattern table looking for a match
local c1, c2, c3, c4; -- captures in the 'pattern' from the pattern table go here
c1, c2, c3, c4 = source:match (pattern[i][1]); -- one or more captures set if source matches pattern[i])
if c1 then -- c1 always set on match
code = c1; -- first capture is always code
t = {
[pattern[i][2] or 'x'] = c2, -- fill the table of captures with the rest of the captures
[pattern[i][3] or 'x'] = c3, -- take index names from pattern table and assign sequential captures
[pattern[i][4] or 'x'] = c4, -- index name may be nil in pattern[i] table so "or 'x'" spoofs a name for this index in this table
};
script = t.s or ''; -- translate table contents to named variables;
region = t.r or ''; -- absent table entries are nil so set named IETF parts to empty string for concatenation
variant= t.v or '';
private = t.p or '';
break; -- and done
end
end
if not code then
return nil, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_tag, {source}); -- 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 (override_table[code] or lang_table[code] or synonym_table[code] or lang_dep_table[code]) then
return nil, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_code, {code}); -- invalid language code, don't know about the others (don't care?)
end
if synonym_table[code] then -- if 639-2/639-2T code has a 639-1 synonym
table.insert (maint_cats, substitute (cfg.get_ietf_parts_t.maint_promo_cat, {code}));
table.insert (maint_msgs, substitute (cfg.get_ietf_parts_t.maint_promo_msg, {code, synonym_table[code]}));
code = synonym_table[code]; -- use the synonym
end
if is_set (script) then
if is_set (args_script) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_scr; -- both code with script and |script= not allowed
end
else
script = args_script or ''; -- use args.script if provided
end
if is_set (script) then
script = script:lower(); -- ensure that we use and return lower case version of this
if not script_table[script] then
return code, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_scr_code, {script, code}); -- language code OK, invalid script, don't know about the others (don't care?)
end
end
if suppressed_table[script] then -- ensure that code-script does not use a suppressed script
if in_array (code, suppressed_table[script]) then
return code, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.script_code, {script, code}); -- language code OK, script is suppressed for this code
end
end
if is_set (region) then
if is_set (args_region) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_reg; -- both code with region and |region= not allowed
end
else
region = args_region or ''; -- use args.region if provided
end
if is_set (region) then
region = region:lower(); -- ensure that we use and return lower case version of this
if not region_table[region] then
return code, script, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_reg_code, {region, code});
end
end
if is_set (variant) then
if is_set (args_variant) then
return code, nil, nil, nil, nil, cfg.get_ietf_parts_t.redundant_var; -- both code with variant and |variant= not allowed
end
else
variant = args_variant or ''; -- use args.variant if provided
end
if is_set (variant) then
variant = variant:lower(); -- ensure that we use and return lower case version of this
if not variant_table[variant] then -- make sure variant is valid
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var, {variant});
end -- does this duplicate/replace tests in lang() and lang_xx()?
if is_set (script) then -- if script set it must be part of the 'prefix'
if not in_array (table.concat ({code, '-', script}), variant_table[variant]['prefixes']) then
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code_scr, {variant, code, script});
end
elseif is_set (region) then -- if region set, there are some prefixes that require lang code and region (en-CA-newfound)
if not in_array (code, variant_table[variant]['prefixes']) then -- first see if lang code is all that's required (en-oxendict though en-GB-oxendict is preferred)
if not in_array (table.concat ({code, '-', region}), variant_table[variant]['prefixes']) then -- now try for lang code and region (en-CA-newfound)
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code_reg, {variant, code, region});
end
end
else -- cheap way to determine if there are prefixes; fonipa and others don't have prefixes; # operator always returns 0
if variant_table[variant]['prefixes'][1] and not in_array (code, variant_table[variant]['prefixes']) then
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_var_code, {variant, code});
end
end
end
if is_set (private) then
private = private:lower(); -- ensure that we use and return lower case version of this
if not override_table[table.concat ({code, '-x-', private})] then -- make sure private tag is valid; note that index
return code, script, region, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_pri, {private});
end
end
return code, script, region, variant, private, nil; -- return the good bits; make sure that msg is nil
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
--[[--------------------------< D I V _ M A R K U P _ A D D >--------------------------------------------------
Adds <i> and </i> tags to list-item text or to implied <p>..</p> text. Mixed not supported.
]]
local function div_markup_add (text, style)
if text:find ('^\n[%*:;#]') then -- look for list markup; list markup must begin at start of text
if 'italic' == style then
return text:gsub ('(\n[%*:;#]+)([^\n]+)', '%1<i>%2</i>'); -- insert italic markup at each list item
else
return text;
end
end
if text:find ('\n+') then -- look for any number of \n characters in text
text = text:gsub ('([^\n])\n([^\n])', '%1 %2'); -- replace single newline characters with a space character which mimics MediaWiki
if 'italic' == style then
text = text:gsub('[^\n]+', '<p><i>%1</i></p>'); -- insert p and italic markup tags at each implied p (two or more consecutive '\n\n' sequences)
else
text = text:gsub ('[^\n]+', '<p>%1</p>'); -- insert p markup at each implied p
text = text:gsub ('\n', ''); -- strip newline characters
end
end
return text;
end
--[[--------------------------< T I T L E _ W R A P P E R _ M A K E >------------------------------------------
Makes a <span title="<title text>"><content_text></span> or <div title="<title text>"><content_text></div> where
<title text> is in the tool-tip in the wiki's local language and <content_text> is non-local-language text in
HTML markup. This because the lang= attribute applies to the content of its enclosing tag.
<tag> holds a string 'div' or 'span' used to choose the correct wrapping tag.
]]
local function title_wrapper_make (title_text, content_text, tag)
local wrapper_t = {};
table.insert (wrapper_t, table.concat ({'<', tag})); -- open opening wrapper tag
table.insert (wrapper_t, ' title=\"'); -- begin title attribute
table.insert (wrapper_t, title_text); -- add <title_text>
table.insert (wrapper_t, '\">'); -- end title attribute and close opening wrapper tag
table.insert (wrapper_t, content_text); -- add <content_text>
table.insert (wrapper_t, table.concat ({'</', tag, '>'})); -- add closing wrapper tag
return table.concat (wrapper_t); -- make a big string and done
end
--[[--------------------------< M A K E _ T E X T _ H T M L >--------------------------------------------------
Add the HTML markup to text according to the type of content that it is: <span> or <i> tags for inline content or
<div> tags for block content
The lang= attribute also applies to the content of the tag where it is placed so this is wrong because 'Spanish
language text' is English:
<i lang="es" title="Spanish language text">casa</i>
should be:
<span title="Spanish language text"><i lang="es">casa</i></span>
or for <div>...</div>:
<div title="Spanish language text"><div lang="es"><spanish-language-text></div></div>
]]
local function make_text_html (code, text, tag, rtl, style, size, language)
local html_t = {};
local style_added = '';
local wrapper_tag = tag; -- <tag> gets modified so save a copy for use when/if we create a wrapper span or div
if text:match ('^%*') then
table.insert (html_t, '*'); -- move proto language text prefix outside of italic markup if any; use numeric entity because plain splat confuses MediaWiki
text = text:gsub ('^%*', ''); -- remove the splat from the text
end
if 'span' == tag then -- default HTML tag for inline content
if 'italic' == style then -- but if italic
tag = 'i'; -- change to <i> tags
end
else -- must be div so go
text = div_markup_add (text, style); -- handle implied <p>, implied <p> with <i>, and list markup (*;:#) with <i>
end
table.insert (html_t, table.concat ({'<', tag})); -- open the <i>, <span>, or <div> HTML tag
code = code:gsub ('%-x%-.*', ''); -- strip private use subtag from code tag because meaningless outside of Wikipedia
table.insert (html_t, table.concat ({' lang="', code, '\"'})); -- add language attribute
if (rtl or unicode.is_rtl(text)) and ('ltr' == this_wiki_lang_dir) then -- text is right-to-left on a left-to-right wiki
table.insert (html_t, ' dir="rtl"'); -- add direction attribute for right-to-left languages
elseif not (rtl or unicode.is_rtl(text)) and ('rtl' == this_wiki_lang_dir) then -- text is left-to-right on a right-to-left wiki
table.insert (html_t, ' dir="ltr"'); -- add direction attribute for left-to-right languages
end
if 'normal' == style then -- when |italic=no
table.insert (html_t, ' style=\"font-style: normal;'); -- override external markup, if any
style_added = '\"'; -- remember that style attribute added and is not yet closed
end
if is_set (size) then -- when |size=<something>
if is_set (style_added) then
table.insert (html_t, table.concat ({' font-size: ', size, ';'})); -- add when style attribute already inserted
else
table.insert (html_t, table.concat ({' style=\"font-size: ', size, ';'})); -- create style attribute
style_added = '\"'; -- remember that style attribute added and is not yet closed
end
end
table.insert (html_t, table.concat ({style_added, '>'})); -- close the opening HTML tag
table.insert (html_t, text); -- insert the text
table.insert (html_t, table.concat ({'</', tag, '>'})); -- close the 'text' <i>, <span>, or <div> HTML tag
if is_set (language) then -- create a <title_text> string for the title= attribute in a wrapper span or div
local title_text;
if 'zxx' == code then -- special case for this tag 'no linguistic content'
title_text = substitute ('$1 $2', {language, cfg.make_text_html_t.zxx}); -- not a language so don't use 'language' in title text
elseif mw.ustring.find (language, 'languages', 1, true) then
title_text = substitute ('$1 $2', {language, cfg.make_text_html_t.collective}); -- for collective languages
else
title_text = substitute ('$1-$2', {language, cfg.make_text_html_t.individual}); -- for individual languages
end
return title_wrapper_make (title_text, table.concat (html_t), wrapper_tag);
else
return table.concat (html_t);
end
end
--[=[-------------------------< M A K E _ C A T E G O R Y >----------------------------------------------------
For individual language, <language>, returns:
[[Category:Articles containing <language>-language text]]
For English:
[[Category:Articles containing explicitly cited English-language text]]
For ISO 639-2 collective languages (and for 639-1 bh):
[[Category:Articles with text in <language> languages]]
]=]
local function make_category (code, language_name, nocat, name_get)
if ((0 ~= namespace) or nocat) and not name_get then -- only categorize in article space
return ''; -- return empty string for concatenation
end
if mw.ustring.find (language_name, 'languages', 1, true) then
return substitute ('[[$1 $2]]', {cfg.make_category_t.collective_cat, language_name});
end
if this_wiki_lang_tag == code then
return substitute ('[[$1 $2 $3-$4]]', { -- unique category name for the local language
cfg.make_category_t.cat_prefix,
cfg.make_category_t.explicit_cat,
language_name,
cfg.make_category_t.cat_postfix,
});
else
return substitute ('[[$1 $2-$3]]', { -- category for individual languages
cfg.make_category_t.cat_prefix,
language_name,
cfg.make_category_t.cat_postfix,
});
end
end
--[[--------------------------< M A K E _ T R A N S L I T >----------------------------------------------------
Return translit <i lang=xx-Latn>...</i> where xx is the language code; else return empty string.
The value |script= is not used in {{transliteration}} for this purpose; instead it uses |code. Because language scripts
are listed in the {{transliteration}} 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).
This function is used by both lang_xx() and xlit()
lang_xx() always provides code, language_name, and translit; may provide tscript; never provides style
xlit() always provides language_name, translit, and one of code or tscript, never both; always provides style
For {{transliteration}}, style only applies when a language code is provided.
]]
local function make_translit (code, language_name, translit, std, tscript, style, engvar)
local title_t = lang_data.translit_title_table; -- table of transliteration standards and the language codes and scripts that apply to those standards
local title_text = ''; -- tool tip text for title= attribute
std = std and std:lower(); -- lower case for table indexing
if not is_set (std) and not is_set (tscript) then -- when neither standard nor script specified
title_text = language_name; -- write a generic tool tip
if not mw.ustring.find (language_name, 'languages', 1, true) then -- collective language names (plural 'languages' is part of the name)
title_text = substitute ('$1-$2', {title_text, cfg.misc_text_t.language}); -- skip this text (individual and macro languages only)
end
title_text = substitute ('$1 $2', {title_text, mw.ustring.lower (cfg.engvar_t[engvar]['romanisz_lc'])}); -- finish the tool tip; use romanization when neither script nor standard supplied
elseif is_set (std) and is_set (tscript) then -- when both are specified
if title_t[std] then -- and if standard is legitimate
if title_t[std][tscript] then -- and if script for that standard is legitimate
if script_table[tscript] then
title_text = substitute ('$1$2 ($3 $4) $5', { -- add the appropriate text to the tool tip
title_text,
title_t[std][tscript:lower()],
script_table[tscript],
cfg.make_translit_t.script,
cfg.make_translit_t.transliteration,
});
else
title_text = title_text .. title_t[std]['default']; -- use the default if script not in std table; TODO: maint cat? error message because script not found for this standard?
end
else
title_text = title_text .. title_t[std]['default']; -- use the default if script not in std table; TODO: maint cat? error message because script not found for this standard?
end
else
return ''; -- invalid standard, setup for error message
end
elseif is_set (std) then -- translit-script not set, use language code
if not title_t[std] then return ''; end -- invalid standard, setup for error message
if title_t[std][code] then -- if language code is in the table (xlit may not provide a language code)
title_text = substitute ('$1$2 ($3 $4) $5', { -- add the appropriate text to the tool tip
title_text,
title_t[std][code:lower()],
language_name,
cfg.misc_text_t.language,
cfg.make_translit_t.transliteration,
});
else -- code doesn't match
title_text = title_text .. title_t[std]['default']; -- so use the standard's default
end
else -- here if translit-script set but translit-std not set
if title_t['no_std'][tscript] then
title_text = title_text .. title_t['no_std'][tscript]; -- use translit-script if set
elseif title_t['no_std'][code] then
title_text = title_text .. title_t['no_std'][code]; -- use language code
else
if is_set (tscript) then
title_text = substitute ('$1$2-$3 $4', { -- write a script tool tip
title_text,
language_name,
cfg.make_translit_t.script,
cfg.make_translit_t.transliteration,
});
elseif is_set (code) then
if not mw.ustring.find (language_name, 'languages', 1, true) then -- collective language names (plural 'languages' is part of the name)
title_text = substitute ('$1-$2', { -- skip this text (individual and macro languages only)
title_text,
cfg.misc_text_t.language,
});
end
title_text = substitute ('$1 $2', { -- finish the tool tip
title_text,
cfg.make_translit_t.transliteration,
});
else
title_text = substitute ('$1 $2', { -- generic tool tip (can we ever get here?)
title_text,
cfg.make_translit_t.transliteration,
});
end
end
end
local tag
if is_set (code) then -- when a language code is provided (always with {{lang-??}} templates, not always with {{transliteration}})
code = code:match ('^(%a%a%a?)'); -- strip all subtags leaving only the language subtag
if not style then -- nil for the default italic style
tag = '<i lang="%s-Latn">%s</i>'
else
tag = '<span style="font-style: %s" lang="%s-Latn">%s</span>' -- non-standard style, construct a span tag for it
tag = string.format(tag, style, "%s", "%s")
end
tag = string.format(tag, code, "%s")
else
tag = '<span>%s</span>' -- when no language code: no lang= attribute, not italic ({{transliteration}} only)
end
tag = string.format(tag, translit) -- add the translit text
if '' == title_text then -- when there is no need for a tool-tip
return tag; -- done
else
title_text = cfg.engvar_sel_t.gb == engvar and title_text:gsub ('([Rr]omani)z', '%1s') or title_text; -- gb eng when engvar specifies gb eng; us eng else
return title_wrapper_make (title_text, tag, 'span'); -- wrap with a tool-tip span and done
end
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''''' unless |italic=unset or |italic=invert.
]]
local function validate_text (template, args)
if not is_set (args.text) then
return make_error_msg (cfg.validate_text_t.no_text, args, template);
end
if args.text:find ("%f[\']\'\'\'\'%f[^\']") or args.text:find ("\'\'\'\'\'[\']+") then -- because we're looking, look for 4 appostrophes or 6+ appostrophes
return make_error_msg (cfg.validate_text_t.malformed_markup, args, template);
end
local style = args.italic;
if (cfg.keywords_t.unset ~= style) and (cfg.keywords_t.invert ~=style) then
if args.text:find ("%f[\']\'\'%f[^\']") or args.text:find ("%f[\']\'\'\'\'\'%f[^\']") then -- italic but not bold, or bold italic
return make_error_msg (cfg.validate_text_t.italic_markup, args, template);
end
end
end
--[[--------------------------< R E N D E R _ M A I N T >------------------------------------------------------
Render mainenance messages and categories.
]]
local function render_maint (nocat)
local maint = {};
if 0 < #maint_msgs then -- when there are maintenance messages
table.insert (maint, table.concat ({'<span class="lang-comment" style="font-style: normal; display: none; color: #33aa33; margin-left: 0.3em;">'})); -- opening <span> tag
for _, msg in ipairs (maint_msgs) do
table.insert (maint, table.concat ({msg, ' '})); -- add message strings
end
table.insert (maint, '</span>'); -- close the span
end
if (0 < #maint_cats) and (0 == namespace) and not nocat then -- when there are maintenance categories; article namespace only
for _, cat in ipairs (maint_cats) do
table.insert (maint, table.concat ({'[[Category:', cat, ']]'})); -- format and add the categories
end
end
return table.concat (maint);
end
--[[--------------------------< P R O T O _ P R E F I X >------------------------------------------------------
For proto languages, text is prefixed with a splat. We do that here as a flag for make_text_html() so that a splat
will be rendered outside of italic markup (if used). If the first character in text here is already a splat, we
do nothing.
proto_param is boolean or nil; true adds splat prefix regardless of language name; false removes and inhibits
regardless of language name; nil does nothing; presumes that the value in text is correct but removes extra splac.
]]
local function proto_prefix (text, language_name, proto_param)
if false == proto_param then -- when forced by |proto=no
return text:gsub ('^%**', ''); -- return text without splat prefix regardless of language name or existing splat prefix in text
elseif (language_name:find ('^Proto%-') or (true == proto_param)) then -- language is a proto or forced by |proto=yes
return text:gsub ('^%**', '*'); -- prefix proto-language text with a splat; also removes duplicate prefixing splats
end
return text:gsub ('^%*+', '*'); -- return text unmolested except multiple splats reduced to one splat
end
--[[--------------------------< H A S _ P O E M _ T A G >------------------------------------------------------
Looks for a poem strip marker in text; returns true when found; false else.
Auto-italic detection disabled when text has poem stripmarker because it is not possible for this code to know
the content that will replace the stripmarker.
]]
local function has_poem_tag (text)
return text:find ('\127[^\127]*UNIQ%-%-poem%-[%a%d]+%-QINU[^\127]*\127') and true or false;
end
--[[--------------------------< H T M L _ T A G _ S E L E C T >------------------------------------------------
Inspects content of and selectively trims text. Returns text and the name of an appropriate HTML tag for text.
If text contains:
\n\n text has implied <p>..</p> tags - trim leading and trailing whitespace and return
If text begins with list markup:
\n* unordered
\n; definition
\n: definition
\n# ordered
trim all leading whitespace except \n and trim all trailing whitespace
If text contains <poem>...</poem> stripmarker, return text unmodified and choose <div>..</div> tags because
the stripmarker is replaced with text wrapped in <div>..</div> tags.
If the text contains any actual <div>...</div> tags, then it's again returned unmodified and <div>...</div>
tags are used to wrap it, to prevent div/span inversion.
]]
local function html_tag_select (text)
local tag;
if has_poem_tag (text) then -- contains poem stripmarker (we can't know the content of that)
tag = 'div'; -- poem replacement is in div tags so lang must use div tags
elseif text:find ('<div') then -- reductive; if the text contains a div tag, we must use div tags
tag = 'div';
elseif mw.text.trim (text):find ('\n\n+') then -- contains implied p tags
text = mw.text.trim (text); -- trim leading and trailing whitespace characters
tag = 'div'; -- must be div because span may not contain p tags (added later by MediaWiki); poem replacement is in div tags
elseif text:find ('\n[%*:;%#]') then -- if text has list markup
text = text:gsub ('^[\t\r\f ]*', ''):gsub ('%s*$', ''); -- trim all whitespace except leading newline character '\n'
tag = 'div'; -- must be div because span may not contain ul, dd, dl, ol tags (added later by MediaWiki)
else
text = mw.text.trim (text); -- plain text
tag = 'span'; -- so span is fine
end
return text, tag;
end
--[[--------------------------< V A L I D A T E _ P R O T O >--------------------------------------------------
Validates value assigned to |proto=; permitted values are yes and no; yes returns as true, no returns as false,
empty string (or parameter omitted) returns as nil; any other value returns nil with <proto_param> as second
return value for use in error message.
]]
local function validate_proto (proto_param)
if cfg.keywords_t.affirmative == proto_param then
return true;
elseif cfg.keywords_t.negative == proto_param then
return false;
elseif is_set (proto_param) then
return nil, proto_param; -- |proto= something other than 'yes' or 'no'
else
return nil; -- missing or empty
end
end
--[[--------------------------< L A N G U A G E _ N A M E _ G E T >--------------------------------------------
Common function to return language name from the data set according to IETF tag.
Returns language name if found in data tables; nil else.
]]
local function language_name_get (ietf, code, cat)
ietf = ietf:lower(); -- ietf:lower() because format_ietf_tag() returns mixed case
local name; -- remains nil if not found
if override_table[ietf] then -- look for whole IETF tag in override table
name = override_table[ietf];
elseif override_table[code] then -- not there so try basic language tag
name = override_table[code];
elseif lang_table[code] then -- shift to IANA active tag/name table
name = lang_table[code];
elseif lang_dep_table[code] then -- try the IANA deprecated tag/name table
name = lang_dep_table[code];
end
return name; -- name from data tables or nil
end
--[[--------------------------< T E X T _ S C R I P T _ M A T C H _ T E S T >----------------------------------
IETF script subtag should match the script of the <text>. This module does not attempt to know all scripts and
what they look like. It does know what Latn script looks like so when <text> is written using other than the Latn
script, the IETF script subtag, if present, should not be Latn.
Conversely, when <text> is written using the Latn script, the IETF script subtag, if present, should be Latn.
For the purposes of this test, Latf (Fraktur) and Latg (Gaelic) are considered to be equivalent to Latn because
unicode treats these two scripts as font-specific variants of Latn.
Returns an error message when mismatch detected; nil else.
]]
local function text_script_match_test (script, is_latn_text, pos, char)
local scripts_t = {['latf'] = true, ['latg'] = true, ['latn'] = true}; -- unicode 'latn' scripts; 'latf' and 'latg' are font variants so there are no Fraktur or Gaelic codepoints
if is_set (script) then -- don't bother with the rest of this if <script> is nil or empty string
script = script:lower(); -- lower case to index into <scripts_t>
if is_latn_text then -- when text is wholly Latn script
if not scripts_t[script] then -- but a non-Latn script is specified
return cfg.text_script_match_test_t.latn_txt_mismatch; -- emit an error message
end
else -- when text is not wholly Latn script
if scripts_t[script] then -- but a Latn script is specified
return substitute (cfg.text_script_match_test_t.latn_scr_mismatch, {pos, char}); -- emit an error message with position of first offending character
end
end
end
end
--[[--------------------------< B I N A R Y _ S E A R C H >---------------------------------------------------
conducts a binary search of <ranges_t> for a sub-range that holds <target>.
returns boolean true if a sub-range holding <target> is found; boolean false else.
]]
local function binary_search (target, ranges_t)
local idx_bot = 1; -- initialize to index of first key
local idx_top = sizeof_ranges_t; -- initialize to index of last key (number of keys)
if (target < ranges_t[idx_bot][1]) or (target > ranges_t[idx_top][2]) then -- invalid; target out of range
return; -- abandon
end
local idx_mid; -- calculated index of range midway between top index and bottom index
local flag = false; -- flag to tell us when we've evaluated last (highest) range in <ranges_t>
while 1 do
idx_mid = math.ceil ((idx_bot + idx_top) / 2); -- get the mid-point in the <ranges_t> sequence
if (target >= ranges_t[idx_mid][1]) and (target <= ranges_t[idx_mid][2]) then -- indexed range low value <= target <= indexed range high value
return true; -- we found the range that holds the <target> character; return true
elseif (target > ranges_t[idx_mid][2]) then -- is <target> > indexed range high value?
idx_bot = idx_mid; -- adjust <idx_bot> up
else -- here when <target> less than indexed range low value
idx_top = idx_mid - 1; -- adjust <idx_top> down
end
if flag then
break; -- here when we just evaluated the last range and <target> not found
end
if not flag and (idx_bot == idx_top) then -- set true just before we evaluate the last (highest) range in <ranges_t>
flag = true;
end
end
end
--[[--------------------------< I S _ L A T I N >--------------------------------------------------------------
compare <text> as codepoints to lists of known codepoints accepted as Latn script
returns boolean true and modified <text> when <text> is wrapped in accept-as-written markup
returns boolean true and <text> when codepoint is known
returns boolean false, <text>, non-Latn codepoint position in <text> (left to right), and the codepoint character
when codepoint is not known
TODO: when text has accept-as-written markup, return a non-boolean value to indicate that <text> is not wholly
latn script? Use that return value to create non-Latn HTML lang= attribute because <text> isn't really
latn so lang=und (undetermined)? or instead, omit the -Latn subtag? (without -Latn need to force |italic=yes)
]]
local function is_latin (text, tag)
local count;
text, count = text:gsub ('^%(%((.+)%)%)$', '%1'); -- remove accept-as-written markup if present
if 0 ~= count then
return true, text; -- markup present so assume that <text> is Latn-script
end
local pos = 0; -- position counter for error messaging
for codepoint in mw.ustring.gcodepoint (text) do -- fetch each code point
pos = pos + 1; -- bump the position counter
if not is_latn_data.singles_t[codepoint] and -- codepoint not found in the singles list?
not binary_search (codepoint, is_latn_data.ranges_t) and -- codepoint not a member of a listed range?
not (tag and is_latn_data.specials_t[codepoint] and is_latn_data.specials_t[codepoint][tag]) then -- not a language-specific codepoint?
return false, text, pos, mw.ustring.char (codepoint); -- codepoint not known; return false with codepoint position and character representation
end
end
return true, text; -- is known; return <text>
end
--[[--------------------------< _ L A N G >--------------------------------------------------------------------
Entry point for {{lang}}.
There should be no reason to set parameters in the {{lang}} {{#invoke:}}
<includeonly>{{#invoke:lang|lang}}</includeonly>
Parameters are received from the template's frame (parent frame).
]]
local function _lang (args)
local out = {};
local language_name; -- used to make category names
local category_name; -- same as language_name except that it retains any parenthetical disambiguators (if any) from the data set
local subtags = {}; -- IETF subtags script, region, variant, and private
local code; -- the language code
local msg; -- for error messages
local tag = 'span'; -- initial value for make_text_html()
local template = args.template or cfg.templates_t.lang;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
validate_cat_args (args); -- determine if categorization should be suppressed
if args[1] and args.code then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {'1', cfg.lang_t.conflict_n_param_types.code}), args, template);
else
args.code = args[1] or args.code; -- prefer args.code
end
if args[2] and args.text then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {'2', cfg.lang_t.conflict_n_param_types.text}), args, template);
else
args.text = args[2] or args.text; -- prefer args.text
end
msg = validate_text (template, args); -- ensure that |text= is set
if is_set (msg) then -- msg is an already-formatted error message
return msg;
end
args.text, tag = html_tag_select (args.text); -- inspects text; returns appropriate HTML tag with text trimmed accordingly
args.rtl = args.rtl == cfg.keywords_t.affirmative; -- convert to boolean: 'yes' -> true, other values -> false
args.proto, msg = validate_proto (args.proto); -- return boolean, or nil, or nil and error message flag
if msg then
return make_error_msg (substitute (cfg.lang_t.invalid_proto, {msg}), args, template);
end
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code); -- |script=, |region=, |variant= not supported because they should be part of args.code ({{{1}}} in {{lang}})
if msg then
return make_error_msg (msg, args, template);
end
local is_latn_text, pos, char;
is_latn_text, args.text, pos, char= is_latin (args.text, code); -- make a boolean
msg = text_script_match_test (subtags.script, is_latn_text, pos, char)
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if nil == args.italic then -- nil when |italic= absent or not set or |italic=default; args.italic controls
args.italic = 'inherit'; -- italic not set; inherit current style
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
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles
language_name = language_name_get (args.code, code, true); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
if cfg.keywords_t.invert == args.italic and 'span' == tag then -- invert only supported for in-line content
args.text = invert_italics (args.text)
end
args.text = proto_prefix (args.text, language_name, args.proto); -- prefix proto-language text with a splat
table.insert (out, make_text_html (args.code, args.text, tag, args.rtl, args.italic, args.size, language_name));
table.insert (out, render_maint (args.nocat)); -- maintenance messages and categories
return table.concat (out); -- put it all together and done
end
--[[--------------------------< L A N G >----------------------------------------------------------------------
Entry point for {{lang}}.
There should be no reason to set parameters in the {{lang}} {{#invoke:}}
<includeonly>{{#invoke:lang|lang}}</includeonly>
Parameters are received from the template's frame (parent frame).
]]
local function lang (frame)
local args_t = getArgs (frame, { -- this code so that we can detect and handle wiki list markup in text
valueFunc = function (key, value)
if 2 == key or 'text' == key then -- the 'text' parameter; do not trim wite space
return value; -- return untrimmed 'text'
elseif value then -- all other values: if the value is not nil
value = mw.text.trim (value); -- trim whitespace
if '' ~= value then -- empty string when value was only whitespace
return value;
end
end
return nil; -- value was empty or contained only whitespace
end -- end of valueFunc
});
args_t.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang|...}}
local msg = parameter_validate (args_t, cfg.templates_t.lang); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args_t, cfg.templates_t.lang); -- when template has unsupported params, abandon with error message
end
return _lang (args_t);
end
--[[--------------------------< T R A N S L A T I O N _ M A K E >----------------------------------------------
Stand-alone function to create literal translation of main text.
Also used by {{lang-x2}}.
]]
local function translation_make (args_t)
local translation_t = {', '}; -- initialize output
if 'none' ~= args_t.label then -- if we want a label
table.insert (translation_t, '<small>'); -- open the <small> HTML tag
if cfg.keywords_t.negative == args_t.link then
table.insert (translation_t, substitute ('<abbr title="$1">$2</abbr>', {cfg.translation_make_t.lit_xlation, cfg.translation_make_t.lit_abbr})); -- unlinked form
else
table.insert (translation_t, make_wikilink (cfg.translation_make_t.lit_xlation, cfg.translation_make_t.lit_abbr)); -- linked form
end
table.insert (translation_t, " </small>"); -- close the <small> HTML tag
end
table.insert (translation_t, table.concat ({''', args_t.translation, '''})); -- use HTML entities to avoid wiki markup confusion
return table.concat (translation_t); -- make a big string and done
end
--[[--------------------------< _ L A N G _ X X >--------------------------------------------------------------
For the {{lang-??}} templates, the only parameter required to be set in the template is the language code. All
other parameters can, usually should, be written in the template call. For {{lang-??}} templates for languages
that can have multiple writing systems, it may be appropriate to set |script= as well.
For each {{lang-??}} template choose the appropriate entry-point function so that this function knows the default
styling that should be applied to text.
For normal, upright style:
<includeonly>{{#invoke:lang|lang_xx_inherit|code=xx}}</includeonly>
For italic style:
<includeonly>{{#invoke:lang|lang_xx_italic|code=xx}}</includeonly>
All other parameters should be received from the template's frame (parent frame)
Supported parameters are:
|code = (required) the IANA language code
|script = IANA script code; especially for use with languages that use multiple writing systems
|region = IANA region code
|variant = IANA variant code
|text = (required) the displayed text in language specified by code
|link = boolean false ('no') does not link code-spcified language name to associated language article
|rtl = boolean true ('yes') identifies the language specified by code as a right-to-left language
|nocat = boolean true ('yes') inhibits normal categorization; error categories are not affected
|cat = boolian false ('no') opposite form of |nocat=
|italic = boolean true ('yes') renders displayed text in italic font; boolean false ('no') renders displayed text in normal font; not set renders according to initial_style_state
|lit = text that is a literal translation of text
|label = 'none' to suppress all labeling (language name, 'translit.', 'lit.')
any other text replaces language-name label - automatic wikilinking disabled
for those {{lang-??}} templates that support transliteration (those templates where |text= is not entirely latn script):
|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-??}}, the positional parameters are:
{{{1}}} text
{{{2}}} transliterated text
{{{3}}} literal translation text
no other positional parameters are allowed
]]
local function _lang_xx (args, base_template) -- base_template will be either of 'langx' or 'lang-xx'
local out = {};
local language_name; -- used to make display text, article links
local category_name; -- same as language_name except that it retains any parenthetical disambiguators (if any) from the data set
local subtags = {}; -- IETF subtags script, region, and variant
local code; -- the language code
local translit_script_name; -- name associated with IANA (ISO 15924) script code
local translit;
local msg; -- for error messages
local tag = 'span'; -- initial value for make_text_html()
local template = args.template or base_template;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
local text_idx = (cfg.templates_t.langx == base_template) and 2 or 1; -- for {{langx}} 'text' positional parameter is '2'
local translit_idx = (cfg.templates_t.langx == base_template) and 3 or 2;
local xlate_idx = (cfg.templates_t.langx == base_template) and 4 or 3;
if args[text_idx] and args.text then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {translit_idx, cfg.lang_t.conflict_n_param_types.text}), args, template);
else
args.text = args[text_idx] or args.text; -- prefer positional 'text' parameter
end
msg = validate_text (template, 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
args.text, tag = html_tag_select (args.text); -- inspects text; returns appropriate HTML tag with text trimmed accordingly
if args[translit_idx] and args.translit then
return make_error_msg (substitute (cfg.lang_t.conflict_n_param, {translit_idx, cfg.lang_t.conflict_n_param_types.translit}), args, template);
else
args.translit = args[translit_idx] or args.translit -- prefer positional 'translit' parameter
end
args.engvar = cfg.default_engvar;
if args[xlate_idx] and (args.translation or args.lit) then
return make_error_msg (substitute (cfg.lang_xx_t.conflict_n_lit, {translit_idx}), args, template);
elseif args.translation and args.lit then
return make_error_msg (cfg.lang_xx_t.conflict_lit, args, template);
else
args.translation = args[xlate_idx] or args.translation or args.lit; -- prefer positional 'translation' parameter
end
if args.links and args.link then
return make_error_msg (cfg.lang_xx_t.conflict_link, args, template);
else
args.link = args.link or args.links; -- prefer args.link
end
validate_cat_args (args); -- determine if categorization should be suppressed
args.rtl = args.rtl == cfg.keywords_t.affirmative; -- convert to boolean: 'yes' -> true, other values -> false
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (args.code, args.script, args.region, args.variant); -- private omitted because private
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
if args.translit then
local latn, pos, char;
latn, args.translit, pos, char = is_latin (args.translit, (('' ~= subtags.private) and (code .. '-x-' .. subtags.private)) or code);
if not latn then
return make_error_msg (substitute (cfg.lang_xx_t.translit_nonlatn, {pos, char}), args, template);
end
end
local is_latn_text, text, pos, char = is_latin (args.text, code); -- make a boolean
args.text = text; -- may have been modified (accept-as-written markup removed)
msg = text_script_match_test (subtags.script, is_latn_text, pos, char)
if msg then -- if an error detected then there is an error message
return make_error_msg (msg, args, template);
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if cfg.templates_t.langx == base_template then -- auto-italics for {{langx}} templates; adapted from {{lang}} (no support for poem tag)
if nil == args.italic then -- nil when |italic= absent or not set or |italic=default; args.italic controls
args.italic = 'inherit'; -- italic not set; inherit current style
end
else -- {{lang-xx}} does not do auto italics; retained for those wikis that don't support {{langx}}
if nil == args.italic then -- args.italic controls
if is_set (subtags.script) then
if 'latn' == subtags.script then
args.italic = 'italic'; -- |script=Latn; set for font-style:italic
else
args.italic = initial_style_state; -- italic not set; script is not latn; set for font-style:<initial_style_state>
end
else
args.italic = initial_style_state; -- here when |italic= and |script= not set; set for font-style:<initial_style_state>
end
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
args.proto, msg = validate_proto (args.proto); -- return boolean, or nil, or nil and error message flag
if msg then
return make_error_msg (substitute (cfg.lang_t.invalid_proto, {args.proto}), args, template);
end
args.code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles
language_name = language_name_get (args.code, code, true); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
category_name = language_name; -- category names retain IANA parenthetical diambiguators (if any)
language_name = language_name:gsub ('%s+%b()', ''); -- remove IANA parenthetical disambiguators or qualifiers from names that have them
if args.label then
if 'none' ~= args.label then
table.insert (out, table.concat ({args.label, ':'})); -- custom label
end
else
if cfg.keywords_t.negative == args.link then
table.insert (out, language_name); -- language name without wikilink
else
if mw.ustring.find (language_name, 'languages', 1, true) then
table.insert (out, make_wikilink (language_name)); -- collective language name uses simple wikilink
elseif lang_data.article_name[args.code:lower()] then -- is IETF tag in article name over ride?
table.insert (out, make_wikilink (lang_data.article_name[args.code:lower()], language_name)); -- language name with wikilink from override data
elseif lang_data.article_name[code] then -- is language tag in article override
table.insert (out, make_wikilink (lang_data.article_name[code], language_name)); -- language name with wikilink from override data
else
table.insert (out, make_wikilink (language_name)); -- language name with wikilink
end
end
table.insert (out, ':'); -- separator
end
if cfg.keywords_t.invert == args.italic then
args.text = invert_italics (args.text)
end
args.text = proto_prefix (args.text, language_name, args.proto); -- prefix proto-language text with a splat
table.insert (out, make_text_html (args.code, args.text, tag, args.rtl, args.italic, args.size, ('none' == args.label) and language_name or nil))
if is_set (args.translit) and not is_latn_text then -- transliteration; not supported when args.text is wholly latn text (this is an imperfect test)
table.insert (out, ','); -- comma to separate text from translit
if 'none' ~= args.label then
table.insert (out, '<small>');
if script_table[args['translit-script']] then -- when |translit-script= is set, try to use the script's name
translit_script_name = script_table[args['translit-script']];
else
translit_script_name = language_name; -- fall back on language name
end
local translit_title_obj = mw.title.makeTitle (0, substitute ('$1 $2',{cfg.lang_xx_t.romanization, translit_script_name})); -- make a title object; no engvar, article titles use US spelling
if translit_title_obj.exists and (cfg.keywords_t.negative ~= args.link) then
table.insert (out, make_wikilink (substitute ('$1 $2', {cfg.lang_xx_t.romanization, translit_script_name or language_name}),
substitute ('$1', {cfg.engvar_t[args.engvar]['romanisz_pt']})) .. ':'); -- make a wikilink if there is an article to link to; engvar the display text
else
table.insert (out, substitute ('$1:', {cfg.engvar_t[args.engvar]['romanisz_pt']})); -- else plain text per engvar
end
table.insert (out, '</small>'); -- close the small tag
end
translit = make_translit (args.code, language_name, args.translit, args['translit-std'], args['translit-script'], nil, args.engvar)
if is_set (translit) then
table.insert (out, translit);
else
return make_error_msg (substitute ('$1: $2', {cfg.lang_xx_t.invalid_xlit_std, args['translit-std'] or '[missing]'}), args, template);
end
elseif is_set (args.translit) and is_latn_text then -- when creating a transliteration of Latn script <text>
return make_error_msg (cfg.lang_xx_t.xlit_of_latn, args, template); -- emit error message and abandon
end
if is_set (args.translation) then -- translation (not supported in {{lang}})
table.insert (out, translation_make (args));
end
table.insert (out, render_maint(args.nocat)); -- maintenance messages and categories
return table.concat (out); -- put it all together and done
end
--[[--------------------------< L A N G _ X X _ A R G S _ G E T >----------------------------------------------
Common function to get args table from {{lang-??}} templates.
Returns table of args.
Text positional parameters are not trimmed here but are selectively trimmed at html_tag_select().
]]
local function lang_xx_args_get (frame, base_template)
local args_t = getArgs(frame,
{
parentFirst= true, -- parameters in the template override parameters set in the {{#invoke:}}
valueFunc = function (key, value)
if ((cfg.templates_t.langx == base_template) and 2 or 1) == key then -- the 'text' positional parameter; 1 for {{lang-??}}, 2 for {{langx}}; do not trim wite space
return value; -- return untrimmed 'text' positional parameter
elseif value then -- all other values: if the value is not nil
value = mw.text.trim (value); -- trim whitespace
if '' ~= value then -- empty string when value was only whitespace
return value;
end
end
return nil; -- value was empty or contained only whitespace
end -- end of valueFunc
});
return args_t;
end
--[[--------------------------< L A N G _ X X _ I T A L I C >--------------------------------------------------
Entry point for those {{lang-??}} templates that call lang_xx_italic(). Sets the initial style state to italic.
]]
local function lang_xx_italic (frame)
local args = lang_xx_args_get (frame, cfg.templates_t.langxx);
args.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang_xx_italic|...}}
local msg = parameter_validate (args, cfg.templates_t.langxx); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args, cfg.templates_t.langxx); -- when template has unsupported params, abandon with error message
end
initial_style_state = 'italic';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G _ X X _ I T A L I C >------------------------------------------------
Entry point from another module. Sets the initial style state to italic.
]]
local function _lang_xx_italic (args)
initial_style_state = 'italic';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< L A N G _ X X _ I N H E R I T >------------------------------------------------
Entry point for those {{lang-??}} templates that call lang_xx_inherit(). Sets the initial style state to inherit.
]]
local function lang_xx_inherit (frame)
local args = lang_xx_args_get (frame, cfg.templates_t.langxx);
args.fn = nil; -- unset because not supported but this function might have been called by {{lang|fn=lang_xx_inherit|...}}
local msg = parameter_validate (args, cfg.templates_t.langxx); -- verify that all supplied parameters are supported by {{lang-??}}
if msg then
return make_error_msg (msg, args, cfg.templates_t.langxx); -- when template has unsupported params, abandon with error message
end
initial_style_state = 'inherit';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G _ X X _ I N H E R I T >----------------------------------------------
Entry point from another module. Sets the initial style state to inherit.
]]
local function _lang_xx_inherit (args)
initial_style_state = 'inherit';
return _lang_xx (args, cfg.templates_t.langxx);
end
--[[--------------------------< _ L A N G X >------------------------------------------------------------------
Entry point from another module.
]]
local function _langx (args_t)
local langx_data = mw.loadData ('Module:Lang/langx'); -- get necessary data
local rtl_t = langx_data.rtl_t; -- get list of language tags for languages that are rendered right-to-left
local link_t = langx_data.link_t; -- get list of language tags for {{lang-??}} templates that set |link=<something>
local size_t = langx_data.size_t; -- get list of language tags for {{lang-??}} templates that set |size=<something>
local msg = parameter_validate (args_t, cfg.templates_t.langx);
if msg then
return make_error_msg (msg, args_t, cfg.templates_t.langx);
end
args_t.code = args_t[1] or args_t.code; -- get the language tag; must be {{{1}}} or |code=
if not args_t.code then
return make_error_msg (cfg.get_ietf_parts_t.missing_lang_tag, args_t, cfg.templates_t.langx);
end
args_t.rtl = args_t.rtl or (rtl_t[args_t.code] and cfg.keywords_t.affirmative); -- prefer |rtl= in template call, use rtl_t else
args_t.link = args_t.link or link_t[args_t.code]; -- prefer |link= in template call, use link_t felse
args_t.size = args_t.size or size_t[args_t.code]; -- prefer |size= in template call, use size_t else
args_t[1] = nil; -- unset to mimic {{lang-??}} templates which set |code=xx
local lang_subtag = args_t.code; -- use only the base language subtag for unsupported tag test; some args_t.code are modified by |script= etc
return _lang_xx (args_t, cfg.templates_t.langx);
end
--[[--------------------------< L A N G X >--------------------------------------------------------------------
Entry point for {{langx}}.
this function calls _lang_xx() to render non-English text. The {{lang-??}} templates have three positional paramters
but {{langx}} has four:
| 1 | 2 | 3 | 4
{{lang-xx |<text> |<xlit> |<xlat> }}
{{langx |<tag> |<text> |<xlit> |<xlat> }}
The calls to lang_xx_args_get() and _lang_xx() use 'langx' as a flag for those functions to select the proper
positional parameters.
{{lang-??}} depends on the calling template to select 'inherit' or 'italic' to establish the default rendering.
{{langx}} can't do that. The initial version of {{langx}} relied on a list of language tags (inherit_t in ~/langx)
scraped from those {{lang-??}} templates that call lang_xx_inherit() to render text in upright font. langx() now
uses auto-italics code adapted from {{lang}} (doesn't support poem tags).
]]
local function langx (frame)
local args_t = lang_xx_args_get (frame, cfg.templates_t.langx); -- get the arguments; 'langx' is the <base_template> used to decide which positional param is 'text', 'translit', 'lit'
return _langx (args_t);
end
--[[--------------------------< _ I S _ I E T F _ T A G >------------------------------------------------------
Returns true when a language name associated with IETF language tag exists; nil else. IETF language tag must be valid.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Module entry point from another module.
]]
local function _is_ietf_tag (tag) -- entry point when this module is require()d into another
local c, s, r, v, p, err; -- code, script, region, variant, private, error message
c, s, r, v, p, err = get_ietf_parts (tag); -- disassemble tag into constituent part and validate
return ((c and not err) and true) or nil; -- return true when code portion has a value without error message; nil else
end
--[[--------------------------< I S _ I E T F _ T A G >--------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function is_ietf_tag (frame)
return _is_ietf_tag (getArgs (frame)[1]); -- args[1] is the IETF language tag to be tested; also get parent frame
end
--[[--------------------------< I S _ I E T F _ T A G _ F R A M E >--------------------------------------------
Module entry point from an {{#invoke:}}; same as is_ietf_tag() except does not get parameters from the parent
(template) frame. This function not useful when called by {{lang|fn=is_ietf_tag_frame|<tag>}} because <tag>
is in the parent frame.
]]
local function is_ietf_tag_frame (frame)
return _is_ietf_tag (getArgs (frame, {frameOnly = true,})[1]); -- args[1] is the IETF language tag to be tested; do not get parent frame
end
--[[--------------------------< _ N A M E _ F R O M _ T A G >--------------------------------------------------
Returns language name associated with IETF language tag if valid; error message else.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Set invoke's |link= parameter to yes to get wikilinked version of the language name.
Module entry point from another module.
]]
local function _name_from_tag (args)
local subtags = {}; -- IETF subtags script, region, variant, and private
local raw_code = args[1]; -- save a copy of the input IETF subtag
local link = cfg.keywords_t.affirmative == args['link']; -- make a boolean
local label = args.label;
local code; -- the language code
local msg; -- gets an error message if IETF language tag is malformed or invalid
local language_name = '';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (raw_code);
if msg then
local template = (args['template'] and table.concat ({'{{', args['template'], '}}: '})) or ''; -- make template name (if provided by the template)
return make_error_span (template, msg);
end
raw_code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles; private omitted because private
language_name = language_name_get (raw_code, code); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
if 'yes' ~= args.raw then
language_name = language_name:gsub ('%s+%b()', ''); -- remove IANA parenthetical disambiguators or qualifiers from names that have them
end
if link then -- when |link=yes, wikilink the language name
if mw.ustring.find (language_name, 'languages', 1, true) then
language_name = make_wikilink (language_name, label); -- collective language name uses simple wikilink
elseif lang_data.article_name[raw_code:lower()] then -- is IETF tag in article name override?
language_name = make_wikilink (lang_data.article_name[raw_code:lower()], label or language_name); -- language name with wikilink from override data
elseif lang_data.article_name[code] then -- is language tag in article name override?
language_name = make_wikilink (lang_data.article_name[code], label or language_name); -- language name with wikilink from override data
else
language_name = make_wikilink (substitute ('$1 $2', {language_name, cfg.misc_text_t.language}), label or language_name); -- language name with wikilink
end
end
return language_name;
end
--[[--------------------------< N A M E _ F R O M _ T A G >----------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function name_from_tag (frame) -- entry point from an {{#invoke:lang|name_from_tag|<IETF tag>|link=<yes>|template=<template name>}}
return _name_from_tag (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame
end
--[[--------------------------< _ T A G _ F R O M _ N A M E >--------------------------------------------------
Returns the IETF language tag associated with the language name. Spelling of language name must be correct
according to the spelling in the source tables. When a standard language name has a parenthetical disambiguator,
that disambiguator must be omitted (they are not present in the data name-to-tag tables).
Module entry point from another module.
]]
local function _tag_from_name (args) -- entry point from another module
local msg;
if args[1] and '' ~= args[1] then
local data = mw.loadData ('Module:Lang/tag from name'); -- get the reversed data tables TODO: change when going live
local lang = args[1]:lower(); -- allow any-case for the language name (speeling must till be correct)
local tag = data.rev_override_table[lang] or data.rev_lang_table[lang] or data.rev_lang_dep_table[lang]; -- get the code; look first in the override then in the standard
if tag then
return tag, true; -- language name found so return tag and done; second return used by is_lang_name()
else
msg = substitute (cfg.tag_from_name_t.lang_not_found, {args[1]}); -- language name not found, error message
end
else
msg = cfg.tag_from_name_t.missing_lang_name; -- language name not found, error message
end
local template = '';
if args.template and '' ~= args.template then
template = table.concat ({'{{', args['template'], '}}: '}); -- make template name (if provided by the template)
end
return make_error_span (template, msg);
end
--[[--------------------------< T A G _ F R O M _ N A M E >----------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function tag_from_name (frame) -- entry point from an {{#invoke:lang|tag_from_name|<language name>|link=<yes>|template=<template name>}}
local result, _ = _tag_from_name (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame; supress second return used by is_lang_name()
return result;
end
--[[--------------------------< I S _ L A N G _ N A M E >------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function is_lang_name (frame)
local _, result = _tag_from_name (getArgs(frame)) -- pass-on the args table, nothing else; getArgs() so we also get parent frame; supress second return used by tag_from_name()
return result and true or nil;
end
--[[--------------------------< _ X L I T >--------------------------------------------------------------------
Module entry point from another module.
]]
local function _xlit (args)
local title_table = lang_data.translit_title_table; -- table of transliteration standards and the language codes and scripts that apply to those standards
local language_name; -- language name that matches language code; used for tool tip
local translit; -- transliterated text to display
local script; -- IANA script
local msg; -- for when called functions return an error message
local template = args.template or cfg.templates_t.transliteration;
maint_cats = {}; -- initialize because when this module required into another module, these only declared once so only initialzed once
maint_msgs = {};
if is_set (args[3]) then -- [3] set when {{transliteration|code|standard|text}}
args.text = args[3]; -- get the transliterated text
args.translit_std = args[2] and args[2]:lower(); -- get the standard; lower case for table indexing
if not title_table[args.translit_std] then
return make_error_msg (substitute (cfg.transl_t.unrecog_xlit_std, {args.translit_std}), args, template);
end
else
if is_set (args[2]) then -- [2] set when {{transliteration|code|text}}
args.text = args[2]; -- get the transliterated text
else
if args[1] and (args[1]:match ('^%a%a%a?%a?$') or -- args[2] missing; is args[1] a language or script tag or is it the transliterated text?
args[1]:match ('^%a%a%a?%-x%-')) then -- or is args[1] a private-use tag
return make_error_msg (cfg.transl_t.no_text, args, template); -- args[1] is a code so we're missing text
else
args.text = args[1]; -- args[1] is not a code so we're missing that; assign args.text for error message
return make_error_msg (cfg.transl_t.missing_lang_scr, args, template);
end
end
end
if is_set (args[1]) then -- IANA language code used for HTML lang= attribute; or ISO 15924 script code
if args[1]:match ('^%a%a%a?%a?$') or args[1]:match ('^%a%a%a?%-x%-') then -- args[1] has correct form?
args.code = args[1]:lower(); -- use the language/script code; only (2, 3, or 4 alpha characters) or private-use; lower case because table indexes are lower case
else
return make_error_msg (substitute (cfg.transl_t.unrecog_lang_scr, {args[1]}), args, template); -- invalid language / script code
end
else
return make_error_msg (cfg.transl_t.missing_lang_scr, args, template); -- missing language / script code so quit
end
local is_latn_text, pos, char;
is_latn_text, args.text, pos, char= is_latin (args.text, args.code); -- is latn text? strip accept-as-written markup
if not is_latn_text then -- when text is not latn
return make_error_msg (substitute (cfg.lang_xx_t.translit_nonlatn, {pos, char}), args, template); -- abandon with error message
end
args.italic, msg = validate_italic (args);
if msg then
return make_error_msg (msg, args, template);
end
if 'italic' == args.italic then -- 'italic' when |italic=yes; because that is same as absent or not set and |italic=default
args.italic = nil; -- set to nil;
end
args.engvar = cfg.default_engvar;
if override_table[args.code] then -- is code a language code defined in the override table?
language_name = override_table[args.code];
args.code = args.code:match ('^%a%a%a?'); -- if private use, strip all but language subtag
elseif lang_table[args.code] then -- is code a language code defined in the standard language code tables?
language_name = lang_table[args.code];
elseif lang_dep_table[args.code] then -- is code a language code defined in the deprecated language code tables?
language_name = lang_dep_table[args.code];
elseif script_table[args.code] then -- if here, code is not a language code; is it a script code?
language_name = script_table[args.code];
script = args.code; -- code was an ISO 15924 script so use that instead
args.code = ''; -- unset because not a language code
else
return make_error_msg (substitute (cfg.transl_t.unrecog_lang_scr, {args.code}), args, template); -- invalid language / script code
end
-- here only when all parameters passed to make_translit() are valid
return make_translit (args.code, language_name, args.text, args.translit_std, script, args.italic, args.engvar);
end
--[[--------------------------< X L I T >----------------------------------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function xlit (frame)
return _xlit (getArgs(frame));
end
--[[--------------------------< C A T E G O R Y _ F R O M _ T A G >--------------------------------------------
Returns category name associated with IETF language tag if valid; error message else.
All code combinations supported by {{lang}} and the {{lang-??}} templates are supported by this function.
Module entry point from another module.
]]
local function _category_from_tag (args_t)
local subtags = {}; -- IETF subtags script, region, variant, and private
local raw_code = args_t[1]; -- save a copy of the input IETF subtag
local link = cfg.keywords_t.affirmative == args_t.link; -- make a boolean
local label = args_t.label;
local code; -- the language code
local msg; -- gets an error message if IETF language tag is malformed or invalid
local category_name = '';
code, subtags.script, subtags.region, subtags.variant, subtags.private, msg = get_ietf_parts (raw_code);
if msg then
local template = (args_t.template and table.concat ({'{{', args_t.template, '}}: '})) or ''; -- make template name (if provided by the template)
return make_error_span (template, msg);
end
raw_code = format_ietf_tag (code, subtags.script, subtags.region, subtags.variant, subtags.private); -- format to recommended subtag styles; private omitted because private
category_name = language_name_get (raw_code, code); -- get language name; try IETF tag first, then code w/o variant then code w/ variant
category_name = make_category (code, category_name, nil, true):gsub ('[%[%]]', '');
if link then
return table.concat ({'[[:', category_name, ']]'});
else
return category_name;
end
end
--[[--------------------------< C A T E G O R Y _ F R O M _ T A G >--------------------------------------------
Module entry point from an {{#invoke:}}.
]]
local function category_from_tag (frame) -- entry point from an {{#invoke:lang|category_from_tag|<IETF tag>|template=<template name>}}
return _category_from_tag (getArgs (frame)); -- pass-on the args table, nothing else; getArgs() so we also get parent frame
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {
category_from_tag = category_from_tag, -- frame entry points when this module is #invoke:ed into templates/wikitext
lang = lang, -- entry point for {{lang}}
langx = langx, -- entry point for {{langx}}
lang_xx_inherit = lang_xx_inherit, -- entry points for {{lang-??}}
lang_xx_italic = lang_xx_italic,
is_ietf_tag = is_ietf_tag,
is_ietf_tag_frame = is_ietf_tag_frame,
is_lang_name = is_lang_name,
tag_from_name = tag_from_name, -- returns IETF tag associated with language name
name_from_tag = name_from_tag, -- used for template documentation; possible use in ISO 639 name from code templates
xlit = xlit, -- entry point for {{transliteration}}
_category_from_tag = _category_from_tag, -- API entry points when this module is require()d into other modules
_lang = _lang,
_langx = _langx,
_lang_xx_inherit = _lang_xx_inherit,
_lang_xx_italic = _lang_xx_italic,
_is_ietf_tag = _is_ietf_tag,
get_ietf_parts = get_ietf_parts,
_tag_from_name = _tag_from_name,
_name_from_tag = _name_from_tag,
_xlit = _xlit,
_translation_make = translation_make,
};
1t0v429l8ck7oxvfsmdccieyectt3cw
迈克尔·法斯宾德
0
71543
398100
348945
2026-08-07T02:00:15Z
Dostojewskij
28898
+ File:Michael Fassbender by Gage Skidmore 2015.jpg + Category:1977年出生
398100
wikitext
text/x-wiki
[[File:Michael Fassbender by Gage Skidmore 2015.jpg|thumb|迈克尔·法斯宾德]]
'''迈克尔·法斯宾德'''(英语:Michael Fassbender,1977年4月2号-)是一位德裔[[爱尔兰]]男演员,生拉西德,母亲为爱尔兰人。2000年渠参加了电视剧集《兄弟连》个试镜并获得了一个角色。2008年,渠凭拉《饥饿》中个表演获得了英国独立电影奖最佳男演员奖。
[[Category:爱尔兰演员]]
[[Category:1977年出生]]
4kdz6otmdv19g6sig4or7v7ovsv5o3k
Wikipedia:红茶坊
4
89940
398096
397611
2026-08-06T16:50:33Z
Lt2818
23148
/* 吴语Wiki阿要用langx代替lang-xx系列模板? */ 回复
398096
wikitext
text/x-wiki
__NEWSECTIONLINK__
箇里是吴语维基百科个讨论页面,懂'''[[吴语]]'''个朋友请用吴语交流。
覅忘记拿签名注起来。签名用四个波浪线符号<code><nowiki>~~~~</nowiki></code>便可以哉,系统会自动帮侬嵌进去个。
早日个讨论:[[/存档1|存档1]]、[[/存档2|存档2]]、[[/存档3|存档3]]、[[/存档4|存档4]]、[[/存档5|存档5]]、[[/存档6|存档6]]、[[/存档7|存档7]]、[[/存档8|存档8]]
[[Category:维基百科讨论]]
== 翻译[[柏油路]]个辰光碰着[[模板:cite journal]]出毛,啊有人相帮修一修? ==
如题
[[模板:cite journal]]出毛,显示个错误是“package.lua第80行Lua错误:module 'Module:Citation/CS1/Suggestions' not found”。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年5月17号 (六) 17:01 (CST)
:拿s2cid删脱试试看。--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2025年5月17号 (六) 17:12 (CST)
::搞定了。
::谢谢。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年5月17号 (六) 17:16 (CST)
== 吴语Wiki阿要用langx代替lang-xx系列模板? ==
如题,英语咾汉语Wiki已经用langx代替脱lang-xx系列模板哉,伲阿要跟进?langx模板是我已经搬过来哉,要使用个闲话,还要拿模块:Lang改脱,阿有比较懂代码个好相帮看看哪恁改改。参考:[[:zh:Module_talk:Lang#提議以langx模板取代lang-xx系列模板]]--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2025年5月24号 (六) 00:35 (CST)
:可以啊,还好省脱新开一堆<nowiki>{{lang-xx}}</nowiki>模板。
:就是我模板弄不来。{{ping|Lt2818}}侬啊好帮忙调整一记?谢谢。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年6月6号 (五) 18:34 (CST)
::{{done}}--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年6月8号 (日) 17:45 (CST)
:::谢谢!--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年6月8号 (日) 18:09 (CST)
:弗好意思,问声问题,为啥langx贴出来个外文侪是斜体字?--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年6月27号 (五) 11:21 (CST)
::[[:en:Template:Langx]]:“italics for languages that use the Latin alphabet, normal for others”--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年6月30号 (一) 23:40 (CST)
:::好个,了解。
:::只是好奇这个其实--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年7月1号 (两) 12:23 (CST)
:::第個應該是因爲英維本身用个是拉丁字,伲吴语维基用弗着第個設置?--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2025年7月2号 (三) 00:01 (CST)
::::好搭吴语拼音区别开来。看大家意见,改出来便当个。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年7月4号 (五) 00:15 (CST)
::::斜体[[Special:Diff/366847/398095|去落]]唻。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2026年8月7号 (五) 00:50 (CST)
== 从zhwiki伊面要上临时账号个串下头发现会得增加新用户组 ==
就是要增加隻叫“临时账号IP查看者”个用户组([[Meta:Temporary account IP viewers]])……
伲箇面还好要晏一眼上线,好先看看交哪能搞个,顺便帮现在个用户组整合起来。
--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年6月10号 (两) 01:27 (CST)
Meta丄写个最低标准是“已加入6个月且编辑300次”。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年6月10号 (两) 01:28 (CST)
[https://wuu.wikipedia.org/w/index.php?title=Wikipedia:%E6%B2%99%E7%9B%98&oldid=373535 消息来哉],只有得5日天,也就是勒垃 '''9月1号''' 上线。
{{ping|Lt2818|源義信|𣍐匄你儂講我个名|Leiem}}近腔上线过个箇面@一记。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年8月27号 (三) 22:26 (CST)
:管理员应该好调整该隻用户组个。就照牢最低标准来罢。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年8月29号 (五) 08:01 (CST)
== 看到有星用户(或者讲 临时账号)可能勒拉“吹”伊拉个领导人 ==
[[User:~2025-53994-4]]、[[User:~2025-53658-6]]咾啥个,近腔拼仔命写马来西亚相关条目扩展伲吴维个条目面是桩好事体,写个也看得到进步,也有过用眼更加好个词语写个,箇要表扬个。必过伊个编辑经常性只写[[马哈蒂尔·默罕默德]]个成就,回避伊搭仔伊政府个弗好个事体,另外只写其他马来西亚领导人犯个错,也就是讲勒垃吹伊拉伊位领导人。比方讲[https://wuu.wikipedia.org/w/index.php?title=%E7%BB%BF%E9%87%8E%E5%B1%B1%E5%BA%84&oldid=375718 绿野山庄]、[https://wuu.wikipedia.org/w/index.php?title=2000%E5%B9%B4%E8%A5%BF%E5%B7%B4%E4%B8%B9%E5%B2%9B%E7%BB%91%E6%9E%B6%E6%A1%88&oldid=375726 2000年西巴丹岛绑架案]、[https://wuu.wikipedia.org/w/index.php?title=%E6%B2%99%E5%B7%B4%E8%8C%B6&curid=92545&oldid=373636 沙巴茶]里向个“算是官方认证过个大项目”咾啥个,我也畀伊搞进去过。
{{ping|Lt2818|源義信}}管理员,乃朆晓得箇种应该难处理?--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年9月8号 (一) 14:12 (CST)
{{ping|Lt2818|源義信}}管理员,现在发现有跨维基破坏个可能。
今朝么,碰着伊勒垃[https://wuu.wikipedia.org/w/index.php?title=%E5%8D%8A%E5%B1%B1%E8%8A%AD%E7%9B%91%E7%8B%B1&curid=93458&oldid=376647 半山芭监狱]里向直接拿箇监牢搬场个理由送畀马哈蒂尔·穆罕默德,拿我查证下来个结果撤销脱——要是伊勿回绝脱,原先还有直接翻译zhwp个可能性。故咾夜到刚刚跑去其他言话版本个维基翻仔一记,发现存在[[:zh:LTA:LC99]]个可能性。另外,吾刚刚拿章节标题改脱哉,因为发现[[User:Lee Vi Ang]]帮箇星临时账号个编辑差大勿多,原标题呒办法拿相关用户侪圈起来。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年9月13号 (六) 23:09 (CST)
:既然是破坏者,箇末應當拿渠封脫(必過渠應該是馬來西亞人,吳語是哪能寫個,用AI?)。--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2025年9月13号 (六) 23:39 (CST)
::可能AI,部分条目有机翻可能。
::另外,提醒过伊埭遍,伊还分弗清爽“朆”(不曾,修饰动词)、“呒”(没,主要修饰名词)。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年9月14号 (日) 16:24 (CST)
{{ping|Lt2818|源義信}}管理员,㑚好。箇人又来哉,而且还是事体只写一半个……现在么伊直接是编辑一趟就调隻临时账户(对哦,箇啊算[[Wikipedia:手傀儡|濫用多隻號頭]]?),比方讲[[~2025-65275-6]]、[[~2025-65449-1]]、[[~2025-65194-0]]。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年9月19号 (五) 18:31 (CST)
发现箇位用户个IP段老早封过好几趟。上头讲个种种事体,说明到现在仍旧弗会做合作性编辑,好当成破坏者处理。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年9月20号 (六) 18:40 (CST)
{{ping|Lt2818|源義信}}管理员,㑚好,又又又来嘞箇人。
[[~2025-28082-45]]、[[~2025-28319-94]]、[[~2025-27957-30]],勒垃写[[马哈蒂尔·穆罕默德]]、[[纳吉·阿都拉萨]]相关个条目,外加望里向加弗中立个言话。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年10月10号 (五) 22:06 (CST)
== 勒垃改[[Template:bd]],想实现自动添加分类个情况,结果实现弗出来哉哪能 ==
如题。
我勒垃[[Template:bd]]里向用仔两遍个[[Template:BD/isYear]],结果两隻地方随机正常显示(比方讲[[坂本龙一]]、[[夏國璋]]里向一隻生年显示勿出,一隻卒年显示勿出),箇是哪能桩事体?--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年10月13号 (一) 21:19 (CST)
照咾zhwp呌个写法写个,哪能伲头我跑勿出来--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年10月13号 (一) 21:26 (CST)
:弗建议用模板加分类,顶好对标英文维基百科,参照[[:en:WP:TEMPLATECAT]]。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2025年10月16号 (四) 23:36 (CST)
::好个。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2025年10月17号 (五) 13:18 (CST)
== 邀請參與確定Wikifunctions的中文譯名 ==
[[metawiki:Special:MyLanguage/Wikifunctions|Wikifunctions]]是維基媒體運動的新成員,[[wikifunctions:Wikifunctions:Project_chat#Chinese_translation_for_project_name|中文維基媒體社羣正在討論爲Wikifunctions確定中文譯名]],歡迎參與討論。--[[User:魔琴|魔琴]]([[User talk:魔琴|讲张]]) 2025年10月18号 (六) 07:37 (CST)
== "百科全书"好用"万宝全书"个表达替代伐? ==
如题--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2026年1月17号 (六) 20:42 (CST)
:“万宝全书”像是主要指 人学识渊博?--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2026年1月17号 (六) 21:08 (CST)
== 2027丁未年新年标志联合票选一事 ==
各位我不会写吴语,我就写中文好了。先祝大家2026年新春快乐。
中文、越南语维基百科,历年有在春节期间更换春节特别标志的习惯,考虑到春节这一习俗广泛传播,且希望有更多设计的出现。基于此去年春节前夕有中维用户提出联合设计乃至票选纪念标志的想法,越文及朝文维基百科也有一些用户表示了兴趣,考虑到本地社群亦有春节习俗。我在此提议以下事项:
: 1本社群或可考虑也在2027春节期间更换标识,更换具体时间可由社群自由商讨
: 2本社群的春节特别标识,可由各社群人员各自提交设计到联合票选项目页,各社群可以自行根据这些设计,组织票选,以来选出最适合自己社群的设计。
考虑到本社群可能并无换标想法,但这也没关系!也欢迎各位来参与创作。此外值得注意的是,由于现在此案基本由我操办,由于本人不太熟悉元维基事宜,请问关于类似想法,是否直接在元维基创建项目页较为适当,谢谢。
可能提这些有点早,但是毕竟涉及到多社群,并计划长期举行,还是希望早点能够讨论。具体我会直接邀请的社群有本地社群,[[:zh:|中维]]、[[:ja:|日维]]、[[:vi:|越维]]、[[:ko:|韩维]]、[[:nan:|闽南语]]、[[:yue:|粤语]]、[[:cdo:|闽东语]]、[[:lzh:|文言]]、[[:hak:|客家话]]、[[:gan:|赣语]]。
另外注意到本地社群规模较小,不知道具体在本地社群是如何达成类似共识,以及具体如何换标的,希望请多指教。
[[:zh:Wikipedia:互助客栈/其他#2027丁未年新年标志联合票选|中文维基百科原始讨论见此]]。
以上,谢谢。--[[User:Luoniya|Luoniya]]([[User talk:Luoniya|讲张]]) 2026年3月6号 (五) 20:01 (CST)
:各位,有关本事的元维基页面已经建立,详见[[:meta:2027 Lunar New Year Special Logo|此]]--[[User:Luoniya|Luoniya]]([[User talk:Luoniya|讲张]]) 2026年3月13号 (五) 21:53 (CST)
:@[[User:Jason2016426|Jason2016426]] @[[User:Lt2818|Lt2818]] @[[User:クフィ|クフィ]]--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2026年3月13号 (五) 23:50 (CST)
== 内塔尼亚胡,好翻译成列泰那狐吗? ==
这是不是太儿戏了?--[[User:不慎言行非法师魔女|搿里是魔女 Monyu the Witch]]([[User_talk:不慎言行非法师魔女|魔法屋]]) 2026年3月15号 (日) 03:22 (CST)
:系惡作劇,應移動至兩岸三地官方翻譯之一或據吳語發音音譯。--[[User:源義信|源義信]]([[User talk:源義信|讲张]]) 2026年3月15号 (日) 09:56 (CST)
== Call to participate: Proposed baseline Neutral Point of View (NPOV) standard ==
Hello-hello!
I am inviting you to participate in the public discussion regarding a proposed baseline Neutral Point of View (NPOV) standard. The proposed baseline is meant for the Wikipedias which do not yet have an NPOV policy, for these communities to adopt, use, and build upon. [[m:Proposed_baseline_NPOV_standard#Proposed_baseline_NPOV_standard|You can find the proposed text here]].
As your Wikipedia does not seem to have an NPOV policy, we hope that this public discussion and proposed baseline standard will support your project community in adopting one. [[m:Talk:Proposed_baseline_NPOV_standard|You can join the public discussion on meta]]<nowiki>. The timeframe for the discussion is from June 17 - July 15, 2026. Looking forward to engagement from your community and hopefully seeing your community to adopt the Neutral Point of View policy! --~~~~</nowiki>--[[User:KVaidla (WMF)|KVaidla (WMF)]]([[User talk:KVaidla (WMF)|讲张]]) 2026年6月19号 (五) 17:19 (CST)
== [[meta:Abstract_Wikipedia|抽象维基百科]]原来计划直接整合到每個闲话版本个维基百科里向啊?伊连闲话也话勿来就想咾让人用? ==
(这种事恕我正文里直接开国语了,不然我怕直接骂出来)
今天刷到[[:en:WP:Village_pump_(WMF)#Abstract_Wikipedia_goes_somewhat_live_and_already_hosts_unattributed_enwiki_copies...]]後,我才发现,[[:meta:Abstract_Wikipedia|抽象维基百科]]是那种想法很丰满,事实很骨感的项目。
截至今年6月,基金会仍难以解决该项目输出内容的语言结构问题,甚至不如机翻(机翻不会连法语这种大语言都必定翻译错误cuoyu'yan)。尽管称其为“making it much easier to start a local version of the article, instead of writing it from scratch or translating from another language. ”(“这样一来,创建本地化版本的文章就容易多了,不用从头开始写,也不用从基金会原本内测的翻译页面其他语言翻译。”),但这要是按照目前的质量,搞出来不就是[[:sco:|低地苏格兰语维基]]的翻版嘛……
[[Wikipedia:红茶坊/存档8#Enabling_Content_and_Section_translation_tool_in_Wu_Wikipedia|基金会原本的机翻]]再怎么说好歹是句中文句子,是汉语下面哪种语言且不论(测试的时候还真是吴语,现在机翻反而基本只有国语了);和这个机翻相比,基金会这个项目真是……难崩。
就算如此,基金会在英维中仍表示,“In a few months, this will be possible when language communities will be able to integrate Abstract Wikipedia articles into their Wikipedias.”(“几个月后,当各个语言社群能够将“抽象维基百科”条目整合到各自的维基百科中时,这一切就将成为可能。”)。我不知道这个要是全域安装上来,啊有得关闭的方法?现在生怕被人用来批量建立条目试图清除红链,结果建立的条目质量还比不上WuuArticleGenerator甚至MirrorWuu的机翻条目……至少机翻勿会得开头头一句闲话是“'''xxx''' is a (机翻内容)”。
问一问其他管理员。{{ping|Lt2818|クフィ|源義信|p=}}——[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2026年7月12号 (日) 21:19 (CST)
:目标搭工具个搭配弗大对。从现在个技术看,Abstract Wikipedia个目标用LLM实现比较好。--[[User:Lt2818|Lt2818]]([[User talk:Lt2818|讲张]]) 2026年7月15号 (三) 23:52 (CST)
伊拉现在勒垃metawiki浪搞了隻[[Meta:Requests_for_comment/The_future_of_Abstract_Wikipedia|Meta Requests for comment: The future of Abstract Wikipedia]]。--[[User:Jason2016426|Jason2016426]]([[User talk:Jason2016426|讲张]]) 2026年7月16号 (四) 00:12 (CST)
6r0q0tw9yokqu6qp09hxh50kfmbnk0w
江绪林
0
99258
398093
2026-08-06T15:54:32Z
Lt2818
23148
新页面:“'''江绪林'''({{bd|1976年|3月14号|2016年|2月19号}}),[[湖北]][[红安县|红安]]人,政治哲學學者,基督徒<ref>{{Cite web |title=学人{{!}}一位理想主义者的死亡 |url=https://chinadigitaltimes.net/chinese/606207.html |date=2019-02-19}}</ref>。[[中國人民大學]]國際關係學院學士,[[北京大學]]哲學研究所碩士,[[香港浸會大學]]宗教搭哲學系博士。2009年博士毕业之后,来勒[[華東師範大學]]政…”
398093
wikitext
text/x-wiki
'''江绪林'''({{bd|1976年|3月14号|2016年|2月19号}}),[[湖北]][[红安县|红安]]人,政治哲學學者,基督徒<ref>{{Cite web |title=学人{{!}}一位理想主义者的死亡 |url=https://chinadigitaltimes.net/chinese/606207.html |date=2019-02-19}}</ref>。[[中國人民大學]]國際關係學院學士,[[北京大學]]哲學研究所碩士,[[香港浸會大學]]宗教搭哲學系博士。2009年博士毕业之后,来勒[[華東師範大學]]政治系做講師。
江绪林好几届号召人纪念[[六四运动]],畀抓出来过<ref>{{cite news|author1=卡帕,黄思霖|title=曾因纪念六四被抓 华师青年学者江绪林自杀亡|url=http://www.rfa.org/cantonese/news/researcher-02202016080304.html|accessdate=2016-02-22|publisher=自由亞洲電台|date=2016-02-20|archive-date=2017-07-28|archive-url=https://web.archive.org/web/20170728172404/http://www.rfa.org/cantonese/news/researcher-02202016080304.html/|dead-url=no}}</ref>。2016年2月19号,来勒[[新浪微博]]發出遺書之后,勒办公室上吊自殺<ref>{{cite news|title=浸大博士、華東師大學者江緒林自縊亡|url=https://hk.news.yahoo.com/浸大博士-華東師大學者江緒林自縊亡-052300182.html|accessdate=2016-02-22|publisher=星島日報|date=2016-02-20|archive-date=2017-07-14|archive-url=https://web.archive.org/web/20170714141103/https://hk.news.yahoo.com/%E6%B5%B8%E5%A4%A7%E5%8D%9A%E5%A3%AB-%E8%8F%AF%E6%9D%B1%E5%B8%AB%E5%A4%A7%E5%AD%B8%E8%80%85%E6%B1%9F%E7%B7%92%E6%9E%97%E8%87%AA%E7%B8%8A%E4%BA%A1-052300182.html|dead-url=no}}</ref>。遗书压末两条写“上主啊,愿你开启希望之门”“我恐惧,我要喝点白酒”。
==参考==
<references />
==外链==
*江绪林个[https://www.douban.com/people/jiangxulin/ 豆瓣主页]
*江绪林个[http://www.weibo.com/u/1880142780 新浪微博]
[[Category:湖北人]]
[[Category:基督徒]]
84h0i3kvp3o3vlr2pw9fus617g0rxn5