Wikipedia zawiki https://za.wikipedia.org/wiki/Yiebdaeuz MediaWiki 1.47.0-wmf.9 first-letter 媒体 特殊 讨论 用户 用户讨论 Wikipedia Wikipedia讨论 文件 文件讨论 MediaWiki MediaWiki讨论 模板 模板讨论 帮助 帮助讨论 分类 分类讨论 TimedText TimedText talk 模块 模块讨论 Event Event talk 模块:Cite/config 828 14837 43043 2026-07-07T17:44:43Z 内存溢出的猫 7954 From [[zh:Module:Cite/config]] 43043 Scribunto text/plain --[[--------------------------< S E T T I N G S >-------------------------------------------------------------- settings definitions for i18n; translate only the rvalues ]] local settings_t = { err_category = '引文格式1错误:cite module', -- name of category that lists article with Module:Cite errors help = '帮助', -- help link display text for error messages help_text_link = 'Help:引文格式1错误', -- help text for error messages can be found on this page unknown_name = '无法识别引文模板名称“$1”', -- error message; $1 is lowercase value extracted from invoke function name } --[[--------------------------< K N O W N _ T E M P L A T E S _ T >-------------------------------------------- list of all known cs1|2 templates by their lowercase names. key is lowercase template name ]] local known_templates_t = { ['arxiv'] = true, ['av media'] = true, ['av media notes'] = true, ['biorxiv'] = true, ['book'] = true, ['citation'] = true, ['citeseerx'] = true, ['conference'] = true, ['document'] = true, ['encyclopedia'] = true, ['episode'] = true, ['interview'] = true, ['journal'] = true, ['magazine'] = true, ['mailing list'] = true, ['map'] = true, ['medrxiv'] = true, ['news'] = true, ['newsgroup'] = true, ['podcast'] = true, ['press release'] = true, ['report'] = true, ['serial'] = true, ['sign'] = true, ['speech'] = true, ['ssrn'] = true, ['tech report'] = true, ['techreport'] = true, ['thesis'] = true, ['web'] = true, } --[[--------------------------< C I T A T I O N _ C L A S S E S _ T >----------------------------------------- |CitationClass= in the cs1|2 templates gets the lowercase template name except for these for which the canonical template name has multiple words (and the oddity that is class="encyclopaedia" – really ought to fix that in Module:Citation/CS1) key is lowercase canonical template name ]] local citation_classes_t = { ['av media'] = 'audio-visual', ['av media notes'] = 'AV-media-notes', ['encyclopedia'] = 'encyclopaedia', ['mailing list'] = 'mailinglist', ['press release'] = 'pressrelease', ['tech report'] = 'techreport', } --[[--------------------------< E X P O R T S >---------------------------------------------------------------- ]] return { citation_classes_t = citation_classes_t, error_messages_t = error_messages_t, known_templates_t = known_templates_t, settings_t = settings_t, } 7pkxancat2rfylbpush7g5up7b4213k 43065 43043 2026-07-07T18:02:29Z 内存溢出的猫 7954 43065 Scribunto text/plain --[[--------------------------< S E T T I N G S >-------------------------------------------------------------- settings definitions for i18n; translate only the rvalues ]] local settings_t = { err_category = '引文格式1错误:cite module', -- name of category that lists article with Module:Cite errors help = 'bang', -- help link display text for error messages help_text_link = 'Help:引文格式1错误', -- help text for error messages can be found on this page unknown_name = '无法识别引文模板名称“$1”', -- error message; $1 is lowercase value extracted from invoke function name } --[[--------------------------< K N O W N _ T E M P L A T E S _ T >-------------------------------------------- list of all known cs1|2 templates by their lowercase names. key is lowercase template name ]] local known_templates_t = { ['arxiv'] = true, ['av media'] = true, ['av media notes'] = true, ['biorxiv'] = true, ['book'] = true, ['citation'] = true, ['citeseerx'] = true, ['conference'] = true, ['document'] = true, ['encyclopedia'] = true, ['episode'] = true, ['interview'] = true, ['journal'] = true, ['magazine'] = true, ['mailing list'] = true, ['map'] = true, ['medrxiv'] = true, ['news'] = true, ['newsgroup'] = true, ['podcast'] = true, ['press release'] = true, ['report'] = true, ['serial'] = true, ['sign'] = true, ['speech'] = true, ['ssrn'] = true, ['tech report'] = true, ['techreport'] = true, ['thesis'] = true, ['web'] = true, } --[[--------------------------< C I T A T I O N _ C L A S S E S _ T >----------------------------------------- |CitationClass= in the cs1|2 templates gets the lowercase template name except for these for which the canonical template name has multiple words (and the oddity that is class="encyclopaedia" – really ought to fix that in Module:Citation/CS1) key is lowercase canonical template name ]] local citation_classes_t = { ['av media'] = 'audio-visual', ['av media notes'] = 'AV-media-notes', ['encyclopedia'] = 'encyclopaedia', ['mailing list'] = 'mailinglist', ['press release'] = 'pressrelease', ['tech report'] = 'techreport', } --[[--------------------------< E X P O R T S >---------------------------------------------------------------- ]] return { citation_classes_t = citation_classes_t, error_messages_t = error_messages_t, known_templates_t = known_templates_t, settings_t = settings_t, } fgowxewtcqnlvt3mx83xeb4kiwh78sk 模块:Date Convert 828 14838 43044 2026-07-07T17:44:45Z 内存溢出的猫 7954 From [[zh:Module:Date_Convert]] 43044 Scribunto text/plain require('strict') local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local p = {} local function error(template) return '<strong class="error">错误:时间格式不正确</strong>[[Category:Template:' .. template .. '使用錯誤]]' end local function time(format, object) return mw.getCurrentFrame():callParserFunction('#time', format, object) end local function convert(input) input = input :gsub("&nbsp;"," ") :gsub("%s+"," ") :gsub('(%a+)[ ,]*(%d+)', '%1 %2'); local y, m, d, suf local datePatternList = { -- English date format {'%d%d? ?%a+[ ,]*%d+', 'Y-m-d'}, -- 26 Oct 1994 {'%a+ ?%d%d?[ ,]+%d+', 'Y-m-d'}, -- Oct 26, 1994 {'%a+[ ,]*%d%d%d%d+', 'Y-m'}, -- Oct 1994 {'%a+ ?%d%d?', 'Y-m-d'}, -- Oct 26 {'%d%d? *%a+', 'Y-m-d'}, -- 26 Oct -- Slash or hyphen date format {'%d+/%d%d?/%d+', 'Y-m-d'}, -- 1994/10/26 or 10/26/1994 {'%d+%.%d%d?%.%d+', 'Y-m-d'}, -- 1994.10.26 or 26.10.1994 {'%d%d?/%d%d?', 'Y-m-d'}, -- 10/26 {'%d+%-%d%d?%-%d+', 'Y-m-d'}, -- 1994-10-26 or 26-10-94 {'%d%d%d%d+%-%d%d?', 'Y-m'}, -- 1994-10 {'%d%d%d%d', 'Y'}, -- 1994 } y, m, d, suf = string.match(input, '^(%d+)年(%d%d?)月(%d%d?)日(.*)$'); if y then if #y < 4 then y = string.rep(0, 4 - #y) .. y end return time('Y-m-d', y .. '-' .. m .. '-' .. d) , suf end y, m, suf = string.match(input, '^(%d+)年(%d%d?)月(.*)$'); if y then if #y < 4 then y = string.rep(0, 4 - #y) .. y end return time('Y-m', y .. '-' .. m) , suf end y, suf = string.match(input, '^(%d+)年(.*)$'); if y then if #y < 4 then y = string.rep(0, 4 - #y) .. y end return time('Y', y) , suf end m, d, suf = string.match(input, '^(%d%d?)月(%d%d?)日(.*)$'); if m and tonumber(m) then return time('m-d', m .. '-' .. d) , suf end for _, value in ipairs(datePatternList) do local str, suf = string.match(input, '^(' .. value[1] .. ')(.*)$'); if str then return time(value[2], str), suf end end return time('Y-m-d', 'error') end function p._converttime(input, showsuf) local date, suf = convert(input) if (yesno(showsuf)) then return date .. suf else return date end end function p._ChineseDate(args, error) local date, suffix = convert(args[1]) local errorMessage = time('Y-m-d', 'error') suffix = args.suf and suffix or '' if string.match(date, '^%d+%-%d%d%-%d%d$') then return time('Y年Fj日', date):gsub("^0+","") .. suffix end if string.match(date, '^%d+%-%d%d$') then return time('Y年F', date):gsub("^0+","") .. suffix end if string.match(date, '^%d+$') then return time('Y年', date):gsub("^0+","") .. suffix end if string.match(date, '^%d%d%-%d%d$') then return time('Fj日', date):gsub("^0+","") .. suffix end if date == errorMessage and args.error == 'ignore' then return args[1] end --- return error('Chinese_date') return '<strong class="error">错误:时间格式不正确</strong>[[Category:Template:Chinese_date使用錯誤]]' end function p.ChineseDate(frame) local args = getArgs(frame) return p._ChineseDate(args) end function p._ISODate(args, error) local returnval, suf = convert(args[1]) local errorMessage = time('Y-m-d', 'error') if returnval == errorMessage and args.error == 'ignore' then return args[1] end if returnval == errorMessage then --- return error('ISODate') return '<strong class="error">错误:时间格式不正确</strong>[[Category:Template:ISODate使用錯誤]]' end return returnval .. (args.suffix and suf or '') end function p.ISODate(frame) local args = getArgs(frame) return p._ISODate(args) end return p 666p2v0132bledyokhiv18rdycrup3e 模块:Cite 828 14839 43045 2026-07-07T17:44:46Z 内存溢出的猫 7954 From [[zh:Module:Cite]] 43045 Scribunto text/plain -- 源自[[:en:Module:Cite]]的本地化版本。当前基于 https://en.wikipedia.org/w/index.php?title=Module:Cite&oldid=1290436560 -- 本地[[Module:Citation/CS1]]的入口函数citation为全局变量,因此不兼容strict -- require ('strict'); local cfg = mw.loadData ('Module:Cite/config'); --[[--------------------------< 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 module name, message text, help link, and error category. ]] local function make_error_msg (frame, msg) local module_name = frame:getTitle(); -- get the module name for prefix and help-link label local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization local category_link = (0 == namespace) and substitute ('[[Category:$1]]', {cfg.settings_t.err_category}) or ''; return substitute ('<span style="color:#d33">&#x7B;{[[$1|#invoke:$2]]}}错误:$3 ([[:$4|$5]])</span>$6', { module_name, -- the module name with namespace module_name:gsub ('Module:', ''), -- the module name without namespace msg, -- the error message cfg.settings_t.help_text_link, -- help wikilink to text at help page cfg.settings_t.help, -- help wikilink display text category_link -- link to error category (for main namespace errors only) }) end -- 本地化改动。方法来自[[Module:Cite web]] local function patch_frame (original_frame, new_args) local proxyFrame = { getParent = function(self) return original_frame end, getTitle = function(self) return 'Module:Citation/CS1' end, args = new_args } setmetatable(proxyFrame, { __index = function(t, k) if type(original_frame[k]) == 'function' then return function(...) return original_frame[k](original_frame, select(2, ...)) end else return original_frame[k] end end }) return proxyFrame end --[[--------------------------< C I T E >--------------------------------------------------------------------- Function to call Module:Citation/CS1/sandbox with appropriate parameters. For use when an article exceeds the post-expand include size limit. {{#invoke:cite|book|title=Title}} ]] local function cite (frame, template) -- 目前类别参数为英语。若含有非ASCII字符则需改用mw.ustring.lower() template = template:lower(); -- lowercase for table indexes if not cfg.known_templates_t[template] then -- do we recognize this template name? return make_error_msg (frame, substitute (cfg.settings_t.unknown_name, {template})); -- nope; abandon with error message end local config_t = {['CitationClass'] = cfg.citation_classes_t[template] or template}; -- set CitationClass value -- 本地[[Module:Citation/CS1]]与英文维基百科结构不同,只有citation一个入口,且要求传入frame。 -- 它的citation函数会将本层frame的args参数表当作已解析的参数,直接存入内部的config和args变量; -- 随后再解析并校验parent frame的args参数表(即条目页传给{{cite web}}模板的参数),结果将并入内部的args变量。 -- 考虑到本模块会被用户直接在条目中调用,参数不规范的机会远多于模板作者在模板中预设CS1参数的情形, -- 因此应当使用Module:Citation/CS1对于{{cite web}}的校验逻辑。 -- 故选择修改frame变量,将本模块的传入参数伪装成parent frame的参数,以复用相关逻辑。 local newFrame = patch_frame(frame, config_t) return require ('Module:Citation/CS1').citation (newFrame); -- go render the citation end --[[--------------------------< E X P O R T S >--------------------------------------------------------------- ]] return setmetatable({}, {__index = -- returns an empty TABLE whose metatable has the __index set so that, for any given KEY, it returns function(_, template) -- this anonymous function called as function(TABLE, KEY) return function (frame) return cite (frame, template) end; -- which in turn returns a function that calls cite() with the KEY name end }) dl2fwpvrx9w2kgk5ge0n1ifjunm6qrr 模板:Cite Q 10 14840 43046 2026-07-07T17:44:48Z 内存溢出的猫 7954 From [[zh:Template:Cite Q]] 43046 wikitext text/x-wiki <includeonly>{{#invoke:Cite Q|cite_q |qid={{{1}}} <!-- Simple parameters from Wikidata --> | publisher = {{#invoke:WikidataIB |getValue |qid={{{1}}} |P123 |fetchwikidata=ALL |onlysourced=no |noicon=true}} | oclc = {{#invoke:wd|property|{{{1}}}|P243}} | place = {{ #property:P291 |from={{{1}}} }} | doi = {{ #property:P356 |from={{{1}}} }} | issue = {{ #property:P433 |from={{{1}}} }} | pmid = {{ #property:P698 |from={{{1}}} }} | ol = {{#invoke:String|replace|{{#invoke:wd|property|{{{1}}}|P648}}|^OL(.+)$|%1|plain=false}} | arxiv = {{ #property:P818 |from={{{1}}} }} | bibcode = {{wdib |ps=1 |P819 |qid={{{1}}} }}<!-- {{ #property:P819 |from={{{1}}} }} --> | jstor = {{ #property:P888 |from={{{1}}} }} | mr = {{ #property:P889 |from={{{1}}} }} | ssrn = {{ #property:P893 |from={{{1}}} }} | pmc = {{ #property:P932 |from={{{1}}} }} | lccn = {{ #property:P1144 |from={{{1}}} }} | hdl = {{ #property:P1184 |from={{{1}}} }} | ismn = {{ #property:P1208 |from={{{1}}} }} | journal = {{ #property:P1433 |from={{{1}}} }} | citeseerx = {{ #property:P3784 |from={{{1}}} }} | osti = {{ #property:P3894 |from={{{1}}} }} | biorxiv = {{ #property:P3951 |from={{{1}}} }} <!-- Special handling of Wikidata parameters --> | isbn = {{#if: {{ #property:P212 |from={{{1}}} }} <!-- if ISBN 13 --> | {{#invoke:wd|property|{{{1}}}|P212}} <!-- use ISBN 13 --> | {{#invoke:wd|property|{{{1}}}|P957}} <!-- else use ISBN 10 --> }} | others = {{#if: {{ #property:P110 |from={{{1}}} }} <!-- is there an illustrator? --> |Illustrator: {{ #property:P110 |from={{{1}}} }} <!-- use illustrator --> | <!-- else do nothing --> }} <!-- Optionally-local parameters --> | chapter = {{#if: {{{chapter|}}} <!-- is chapter specified? --> | {{{chapter}}} <!-- use locally-specified value --> | {{ #property:P792 |from={{{1}}} }} <!-- else fetch from Wikidata --> }} | date = {{#if: {{{date|}}} <!-- is date specified? --> | {{ISODate|{{{date}}}}} <!-- use date --> | {{#if:{{#invoke:wd|property|raw|{{{1}}}|P577}}|{{ISODate|{{#invoke:wd|property|raw|{{{1}}}|P577}}}}}}<!-- else use date from Wikidata --> }} | series = {{#if: {{{series|}}} <!-- is series specified? --> | {{{series}}} <!-- use series --> | {{ #property:P179 |from={{{1}}} }} <!-- else use series from Wikidata --> }} | volume = {{#if: {{{volume|}}} <!-- is volume specified? --> | {{{volume}}} <!-- use volume --> | {{ #property:P478 |from={{{1}}} }} <!-- else use volume from Wikidata --> }} | title = {{#if: {{ #property:P1476 |from={{{1}}} }} <!-- is there a title --> | {{ #property:P1476 |from={{{1}}} }} <!-- use title --> | {{#if:{{{url|}}}{{ #property:P856 |from={{{1}}} }} |{{#invoke:WikidataIB |getLabel | {{{1}}} }} <!-- don't mix |url= and a wikilinked |title= --> |{{#invoke:WikidataIB |getLink | {{{1}}} }} <!-- else use label from Wikidata --> }} }} | url = {{#if: {{{url|}}} <!-- is url specified? --> | {{{url}}} <!-- use url --> | {{ #property:P856 |from={{{1}}} }} <!-- else use url from Wikidata --> }} | pages = {{{pages|{{ #property:P304 |from={{{1}}} }}}}} }}</includeonly><noinclude> {{documentation}} [[Category:維基數據模板]] [[Category:引用模板|{{PAGENAME}}]] </noinclude> fk7lv3e3o8vt3xn0gkq9cjoayeeg7s1 模板:Wdib 10 14841 43047 2026-07-07T17:44:50Z 内存溢出的猫 7954 From [[zh:Template:wdib]] 43047 wikitext text/x-wiki {{#invoke:WikidataIB|getValue}}<noinclude> {{documentation}} </noinclude> t9d3ehgkq1uwxupd66kuww7i118e6vk 模板:ISODate 10 14842 43048 2026-07-07T17:44:51Z 内存溢出的猫 7954 From [[zh:Template:ISODate]] 43048 wikitext text/x-wiki <includeonly>{{#invoke:Date_Convert|ISODate}}</includeonly><noinclude> {{Doc}} </noinclude> 8f9nl8wnmn6m8u3jm8b1ucssp2ecwx1 模板:Date 10 14843 43049 2026-07-07T17:44:53Z 内存溢出的猫 7954 From [[zh:Template:date]] 43049 wikitext text/x-wiki {{{{{subst|}}}#switch:none |{{{{{subst|}}}#iferror: {{{{{subst|}}}#time:Y_M_d|{{{1|}}} }} | none }} <noinclude><!-- #time: can't handle --></noinclude> |{{{{{subst|}}}#iferror: {{{{{subst|}}}#expr: {{{1|}}}+0 }} |<noinclude><!--not a pure number--></noinclude> |{{{{{subst|}}}#ifexpr: {{{1|}}}+0 > 10000000000000 |<noinclude><!-- a yyyymmddhhmmss timestamp --></noinclude> |{{{{{subst|}}}#ifeq: {{{{{subst|}}}#expr:{{{1|}}}+0}} | {{{1|}}} | none <noinclude><!-- pure number eg 123.456 --></noinclude> | <noinclude><!-- assume yy-mm-dd --></noinclude> }} }} }} |{{{{{subst|}}}#switch: {{lc:{{{2|}}}}} | none | asis=none }} |{{{{{subst|}}}#ifexpr: {{{{{subst|}}}#time:Y|{{{1|}}} }} < 1000 | none }} |{{{{{subst|}}}#switch: {{{{{subst|}}}#time:Ynj|{{{1|}}} }}|100031|110031|130031|140031|150031=none}} |= {{{1|}}}<noinclude><!-- error or "none", so no formatting --></noinclude> |<noinclude><!-- continue with formatting --></noinclude> {{{{{subst|}}}#ifeq:<noinclude><!-- --></noinclude>{{{{{subst|}}}#time:Y|{{{1}}} 2008}}<noinclude><!-- --></noinclude>{{{{{subst|}}}#iferror: {{{{{subst|}}}#ifexpr: {{{1}}}>10000000000000 | no }} | }}<noinclude><!-- --></noinclude>{{{{{subst|}}}#time:Y|{{{1}}} 2004}} |20082004 |<noinclude><!-- no year --></noinclude> {{{{{subst|}}}#ifeq:{{{{{subst|}}}#time:d|{{{1}}} 2036}}|{{{{{subst|}}}#time:d|{{{1}}} }} |<noinclude><!-- month+day --></noinclude>{{{{{subst|}}}#time: {{{{{subst|}}}#switch: {{lc: {{{{{subst|}}}#ifeq:{{{3|}}}|y|L}}{{{2|}}} }} | lmdy | liso | lymd = [[:n月j日|F j]] | mdy | iso | ymd = F j | ldmy | l = [[:n月j日|j F]] | #default = j F }}|{{{1}}} 2000 |en}}<noinclude><!-- default='dmy' or null or "" or unsupported option --></noinclude> |<noinclude><!-- month only --></noinclude>{{{{{subst|}}}#time: {{{{{subst|}}}#switch: {{lc: {{{{{subst|}}}#ifeq:{{{3|}}}|y|L}}{{{2|}}} }} | lmdy | liso | lymd | ldmy | l = [[n月|F]] | #default = F }}|{{{1}}} 2000 |en}}<noinclude><!-- default='dmy'/'mdy'/'ymd'/'iso'/null/""/unsupported opt --></noinclude> }} |<noinclude><!-- with year--></noinclude> {{{{{subst|}}}#if: {{{{{subst|}}}#iferror:{{{{{subst|}}}#time:j|2 {{{1|}}}}}|*D*|{{{{{subst|}}}#iferror:{{{{{subst|}}}#time:j|2000 {{{1|}}}}}|*D*| }}}} |<noinclude><!-- day+month+year --></noinclude>{{{{{subst|}}}#time: {{{{{subst|}}}#switch: {{lc: {{{{{subst|}}}#ifeq:{{{3|}}}|y|L}}{{{2|}}} }} | lmdy = [[:n月j日|F j]], [[Y年|Y]] | mdy = F j, Y | liso = [[Y年|Y-]][[n月j日|m-d]]<noinclude><!-- i.e. [[Y-m-d]] --></noinclude> | iso = Y-m-d | lymd = [[Y年|Y]] [[:n月j日|F j]] | ymd = Y F j | ldmy | l = [[:n月j日|j F]] [[Y年|Y]] | #default = j F Y }}|{{{1|}}} |en}}<noinclude><!-- #default='dmy' or null or "" or unsupported option --></noinclude> |<noinclude><!-- month+year --></noinclude>{{{{{subst|}}}#time: {{{{{subst|}}}#switch: {{lc: {{{{{subst|}}}#ifeq:{{{3|}}}|y|L}}{{{2|}}} }} | lmdy | liso | lymd | ldmy | l = [[:Y年n月|F Y]] | #default = F Y }}|{{{1|}}} |en}}<noinclude><!-- default='dmy'/'iso'/'mdy'/null/""/unsupported option --></noinclude> }} }} }}<noinclude> {{documentation}} </noinclude> 5fy99b16zemhmnlw3irtflxnknsh9n4 模板:Cite Q/doc 10 14844 43050 2026-07-07T17:50:19Z 内存溢出的猫 7954 创建页面,内容为“{{Cite Q|Q140420796}}” 43050 wikitext text/x-wiki {{Cite Q|Q140420796}} 43dto4f2eanaiuampqtufq3ickf751f 模块:WikidataIB/sandbox for Cite Q 828 14845 43051 2026-07-07T17:54:00Z 内存溢出的猫 7954 From [[zh:Module:WikidataIB/sandbox for Cite Q]] 43051 Scribunto text/plain -- Version: 2021-02-06 -- Module to implement use of a blacklist and whitelist for infobox fields -- Can take a named parameter |qid which is the Wikidata ID for the article -- if not supplied, it will use the Wikidata ID associated with the current page. -- Fields in blacklist are never to be displayed, i.e. module must return nil in all circumstances -- Fields in whitelist return local value if it exists or the Wikidata value otherwise -- The name of the field that this function is called from is passed in named parameter |name -- The name is compulsory when blacklist or whitelist is used, -- so the module returns nil if it is not supplied. -- blacklist is passed in named parameter |suppressfields (or |spf) -- whitelist is passed in named parameter |fetchwikidata (or |fwd) require("strict") local p = {} local cdate -- initialise as nil and only load _complex_date function if needed -- Module:Complex date is loaded lazily and has the following dependencies: -- Module:Calendar -- Module:ISOdate -- Module:DateI18n -- Module:I18n/complex date -- Module:Ordinal -- Module:I18n/ordinal -- Module:Yesno -- Module:Formatnum -- Module:Linguistic -- -- The following, taken from https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times, -- is needed to use Module:Complex date which seemingly requires date precision as a string. -- It would work better if only the authors of the mediawiki page could spell 'millennium'. local dp = { [6] = "millennium", [7] = "century", [8] = "decade", [9] = "year", [10] = "month", [11] = "day", } local i18n = { ["errors"] = { ["property-not-found"] = "未找到属性。", ["No property supplied"] = "未找到Wikidata属性。", ["entity-not-found"] = "未找到Wikidata实体。", ["unknown-claim-type"] = "未知声称类型。", ["unknown-entity-type"] = "未知实体类型。", ["qualifier-not-found"] = "未找到修饰词。", ["site-not-found"] = "未找到维基媒体项目。", ["labels-not-found"] = "未找到Wikidata标签。", ["descriptions-not-found"] = "未找到描述。", ["aliases-not-found"] = "未找到别名。", ["unknown-datetime-format"] = "未知日期时间格式。", ["local-article-not-found"] = "此维基尚无此条目", ["dab-page"] = " (消歧义)", }, ["months"] = { "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" }, ["century"] = "世纪", ["BC"] = "公元前", ["BCE"] = "公元前", ["ordinal"] = { [1] = "", [2] = "", [3] = "", ["default"] = "" }, ["filespace"] = "File", ["Unknown"] = "未知", ["NaN"] = "不是数字", -- set the following to the name of a tracking category, -- e.g. "[[Category:Articles with missing Wikidata information]]", or "" to disable: ["missinginfocat"] = "[[Category:缺少維基數據信息的條目]]", ["editonwikidata"] = "编辑维基数据", ["latestdatequalifier"] = function (date) return date .. "之前" end, -- some languages, e.g. Bosnian use a period as a suffix after each number in a date ["datenumbersuffix"] = "", ["list separator"] = "、", ["multipliers"] = { [0] = "", [4] = "万", [8] = "亿", [12] = "兆", } } -- This allows an internationisation module to override the above table if 'en' ~= mw.getContentLanguage():getCode() then require("Module:i18n").loadI18n("Module:WikidataIB/i18n", i18n) end -- This piece of html implements a collapsible container. Check the classes exist on your wiki. local collapsediv = '<div class="mw-collapsible mw-collapsed" style="width:100%; overflow:auto;" data-expandtext="{{int:show}}" data-collapsetext="{{int:hide}}">' -- Some items should not be linked. -- Each wiki can create a list of those in Module:WikidataIB/nolinks -- It should return a table called itemsindex, containing true for each item not to be linked local donotlink = {} local nolinks_exists, nolinks = pcall(mw.loadData, "Module:WikidataIB/nolinks") if nolinks_exists then donotlink = nolinks.itemsindex end -- To satisfy Wikipedia:Manual of Style/Titles, certain types of items are italicised, and others are quoted. -- The submodule [[Module:WikidataIB/titleformats]] lists the entity-ids used in 'instance of' (P31), -- which allows this module to identify the values that should be formatted. -- WikidataIB/titleformats exports a table p.formats, which is indexed by entity-id, and contains the value " or '' local formats = {} local titleformats_exists, titleformats = pcall(mw.loadData, "Module:WikidataIB/titleformats") if titleformats_exists then formats = titleformats.formats end ------------------------------------------------------------------------------- -- Private functions ------------------------------------------------------------------------------- -- ------------------------------------------------------------------------------- -- makeOrdinal needs to be internationalised along with the above: -- takes cardinal number as a numeric and returns the ordinal as a string -- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local makeOrdinal = function(cardinal) local ordsuffix = i18n.ordinal.default if cardinal % 10 == 1 then ordsuffix = i18n.ordinal[1] elseif cardinal % 10 == 2 then ordsuffix = i18n.ordinal[2] elseif cardinal % 10 == 3 then ordsuffix = i18n.ordinal[3] end -- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' -- similarly for 12 and 13, etc. if (cardinal % 100 == 11) or (cardinal % 100 == 12) or (cardinal % 100 == 13) then ordsuffix = i18n.ordinal.default end return tostring(cardinal) .. ordsuffix end ------------------------------------------------------------------------------- -- findLang takes a "langcode" parameter if supplied and valid -- otherwise it tries to create it from the user's set language ({{int:lang}}) -- failing that it uses the wiki's content language. -- It returns a language object ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local findLang = function(langcode) local langobj langcode = mw.text.trim(langcode or "") if mw.language.isKnownLanguageTag(langcode) then langobj = mw.language.new( langcode ) else langcode = mw.getCurrentFrame():callParserFunction('int', {'lang'}) if mw.language.isKnownLanguageTag(langcode) then langobj = mw.language.new( langcode ) else langobj = mw.language.getContentLanguage() end end return langobj end ------------------------------------------------------------------------------- -- _getItemLangCode takes a qid parameter (using the current page's qid if blank) -- If the item for that qid has property country (P17) it looks at the first preferred value -- If the country has an official language (P37), it looks at the first preferred value -- If that official language has a language code (P424), it returns the first preferred value -- Otherwise it returns nothing. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local _getItemLangCode = function(qid) qid = mw.text.trim(qid or ""):upper() if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return end local prop17 = mw.wikibase.getBestStatements(qid, "P17")[1] if not prop17 or prop17.mainsnak.snaktype ~= "value" then return end local qid17 = prop17.mainsnak.datavalue.value.id local prop37 = mw.wikibase.getBestStatements(qid17, "P37")[1] if not prop37 or prop37.mainsnak.snaktype ~= "value" then return end local qid37 = prop37.mainsnak.datavalue.value.id local prop424 = mw.wikibase.getBestStatements(qid37, "P424")[1] if not prop424 or prop424.mainsnak.snaktype ~= "value" then return end return prop424.mainsnak.datavalue.value end ------------------------------------------------------------------------------- -- roundto takes a number (x) -- and returns it rounded to (sf) significant figures ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local roundto = function(x, sf) if x == 0 then return 0 end local s = 1 if x < 0 then x = -x s = -1 end if sf < 1 then sf = 1 end local p = 10 ^ (math.floor(math.log10(x)) - sf + 1) x = math.floor(x / p + 0.5) * p * s -- if it's integral, cast to an integer: if x == math.floor(x) then x = math.floor(x) end return x end ------------------------------------------------------------------------------- -- decimalToDMS takes a decimal degrees (x) with precision (p) -- and returns degrees/minutes/seconds according to the precision ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local decimalToDMS = function(x, p) -- if p is not supplied, use a precision around 0.1 seconds if not tonumber(p) then p = 1e-4 end local d = math.floor(x) local ms = (x - d) * 60 if p > 0.5 then -- precision is > 1/2 a degree if ms > 30 then d = d + 1 end ms = 0 end local m = math.floor(ms) local s = (ms - m) * 60 if p > 0.008 then -- precision is > 1/2 a minute if s > 30 then m = m +1 end s = 0 elseif p > 0.00014 then -- precision is > 1/2 a second s = math.floor(s + 0.5) elseif p > 0.000014 then -- precision is > 1/20 second s = math.floor(10 * s + 0.5) / 10 elseif p > 0.0000014 then -- precision is > 1/200 second s = math.floor(100 * s + 0.5) / 100 else -- cap it at 3 dec places for now s = math.floor(1000 * s + 0.5) / 1000 end return d, m, s end ------------------------------------------------------------------------------- -- decimalPrecision takes a decimal (x) with precision (p) -- and returns x rounded approximately to the given precision -- precision should be between 1 and 1e-6, preferably a power of 10. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local decimalPrecision = function(x, p) local s = 1 if x < 0 then x = -x s = -1 end -- if p is not supplied, pick an arbitrary precision if not tonumber(p) then p = 1e-4 elseif p > 1 then p = 1 elseif p < 1e-6 then p = 1e-6 else p = 10 ^ math.floor(math.log10(p)) end x = math.floor(x / p + 0.5) * p * s -- if it's integral, cast to an integer: if x == math.floor(x) then x = math.floor(x) end -- if it's less than 1e-4, it will be in exponent form, so return a string with 6dp -- 9e-5 becomes 0.000090 if math.abs(x) < 1e-4 then x = string.format("%f", x) end return x end ------------------------------------------------------------------------------- -- formatDate takes a datetime of the usual format from mw.wikibase.entity:formatPropertyValues -- like "1 August 30 BCE" as parameter 1 -- and formats it according to the df (date format) and bc parameters -- df = ["dmy" / "mdy" / "y"] default will be "ymd" -- bc = ["BC" / "BCE"] default will be "BCE" ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local format_Date = function(datetime, dateformat, bc) local datetime = datetime or "1 August 30 BCE" -- in case of nil value -- chop off multiple vales and/or any hours, mins, etc. -- keep anything before punctuation - we just want a single date: local dateval = string.match( datetime, "[%w ]+") local dateformat = string.lower(dateformat or "ymd") -- default to ymd local bc = string.upper(bc or "") -- can't use nil for bc -- we only want to accept two possibilities: BC or default to BCE if bc == "BC" then bc = "&nbsp;" .. i18n["BC"] -- prepend a non-breaking space. else bc = "&nbsp;" .. i18n["BCE"] end local postchrist = true -- start by assuming no BCE local dateparts = {} for word in string.gmatch(dateval, "%w+") do if word == "BCE" or word == "BC" then -- *** internationalise later *** postchrist = false else -- we'll keep the parts that are not 'BCE' in a table dateparts[#dateparts + 1] = word end end if postchrist then bc = "" end -- set AD dates to no suffix *** internationalise later *** local sep = "&nbsp;" -- separator is nbsp local fdate = table.concat(dateparts, sep) -- set formatted date to same order as input -- if we have day month year, check dateformat if #dateparts == 3 then if dateformat == "y" then fdate = dateparts[3] elseif dateformat == "mdy" then fdate = dateparts[2] .. sep .. dateparts[1] .. "," .. sep .. dateparts[3] end elseif #dateparts == 2 and dateformat == "y" then fdate = dateparts[2] end return fdate .. bc end ------------------------------------------------------------------------------- -- dateFormat is the handler for properties that are of type "time" -- It takes timestamp, precision (6 to 11 per mediawiki), dateformat (y/dmy/mdy), BC format (BC/BCE), -- a plaindate switch (yes/no/adj) to en/disable "sourcing circumstances"/use adjectival form, -- any qualifiers for the property, the language, and any adjective to use like 'before'. -- It passes the date through the "complex date" function -- and returns a string with the internatonalised date formatted according to preferences. ------------------------------------------------------------------------------- -- Dependencies: findLang(); cdate(); dp[] ------------------------------------------------------------------------------- local dateFormat = function(timestamp, dprec, df, bcf, pd, qualifiers, lang, adj, model) -- output formatting according to preferences (y/dmy/mdy/ymd) df = (df or ""):lower() -- if ymd is required, return the part of the timestamp in YYYY-MM-DD form -- but apply Year zero#Astronomers fix: 1 BC = 0000; 2 BC = -0001; etc. if df == "ymd" then if timestamp:sub(1,1) == "+" then return timestamp:sub(2,11) else local yr = tonumber(timestamp:sub(2,5)) - 1 yr = ("000" .. yr):sub(-4) if yr ~= "0000" then yr = "-" .. yr end return yr .. timestamp:sub(6,11) end end -- A year can be stored like this: "+1872-00-00T00:00:00Z", -- which is processed here as if it were the day before "+1872-01-01T00:00:00Z", -- and that's the last day of 1871, so the year is wrong. -- So fix the month 0, day 0 timestamp to become 1 January instead: timestamp = timestamp:gsub("%-00%-00T", "-01-01T") -- just in case date precision is missing dprec = dprec or 11 -- override more precise dates if required dateformat is year alone: if df == "y" and dprec > 9 then dprec = 9 end -- complex date only deals with precisions from 6 to 11, so clip range dprec = dprec>11 and 11 or dprec dprec = dprec<6 and 6 or dprec -- BC format is "BC" or "BCE" bcf = (bcf or ""):upper() -- plaindate only needs the first letter (y/n/a) pd = (pd or ""):sub(1,1):lower() if pd == "" or pd == "n" or pd == "f" or pd == "0" then pd = false end -- in case language isn't passed lang = lang or findLang().code -- set adj as empty if nil adj = adj or "" -- extract the day, month, year from the timestamp local bc = timestamp:sub(1, 1)=="-" and "BC" or "" local year, month, day = timestamp:match("[+-](%d*)-(%d*)-(%d*)T") local iso = tonumber(year) -- if year is missing, let it throw an error -- this will adjust the date format to be compatible with cdate -- possible formats are Y, YY, YYY0, YYYY, YYYY-MM, YYYY-MM-DD if dprec == 6 then iso = math.floor( (iso - 1) / 1000 ) + 1 end if dprec == 7 then iso = math.floor( (iso - 1) / 100 ) + 1 end if dprec == 8 then iso = math.floor( iso / 10 ) .. "0" end if dprec == 10 then iso = year .. "-" .. month end if dprec == 11 then iso = year .. "-" .. month .. "-" .. day end -- add "circa" (Q5727902) from "sourcing circumstances" (P1480) local sc = not pd and qualifiers and qualifiers.P1480 if sc then for k1, v1 in pairs(sc) do if v1.datavalue and v1.datavalue.value.id == "Q5727902" then adj = "circa" break end end end -- deal with Julian dates: -- no point in saying that dates before 1582 are Julian - they are by default -- doesn't make sense for dates less precise than year -- we can suppress it by setting |plaindate, e.g. for use in constructing categories. local calendarmodel = "" if tonumber(year) > 1582 and dprec > 8 and not pd and model == "http://www.wikidata.org/entity/Q1985786" then calendarmodel = "julian" end if not cdate then cdate = require("Module:Complex date")._complex_date end local fdate = cdate(calendarmodel, adj, tostring(iso), dp[dprec], bc, "", "", "", "", lang, 1) -- this may have QuickStatements info appended to it in a div, so remove that fdate = fdate:gsub(' <div style="display: none;">[^<]*</div>', '') -- it may also be returned wrapped in a microformat, so remove that fdate = fdate:gsub("<[^>]*>", "") -- there may be leading zeros that we should remove fdate = fdate:gsub("^0*", "") -- if a plain date is required, then remove any links (like BC linked) if pd then fdate = fdate:gsub("%[%[.*|", ""):gsub("]]", "") end -- if 'circa', use the abbreviated form *** internationalise later *** fdate = fdate:gsub('circa ', '<abbr title="circa">c.</abbr>&nbsp;') -- deal with BC/BCE if bcf == "BCE" then fdate = fdate:gsub('BC', 'BCE') end -- deal with mdy format if df == "mdy" then fdate = fdate:gsub("(%d+) (%w+) (%d+)", "%2 %1, %3") end -- deal with adjectival form *** internationalise later *** if pd == "a" then fdate = fdate:gsub(' century', '-century') end return fdate end ------------------------------------------------------------------------------- -- parseParam takes a (string) parameter, e.g. from the list of frame arguments, -- and makes "false", "no", and "0" into the (boolean) false -- it makes the empty string and nil into the (boolean) value passed as default -- allowing the parameter to be true or false by default. -- It returns a boolean. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local parseParam = function(param, default) if type(param) == "boolean" then param = tostring(param) end if param and param ~= "" then param = param:lower() if (param == "false") or (param:sub(1,1) == "n") or (param == "0") then return false else return true end else return default end end ------------------------------------------------------------------------------- -- _getSitelink takes the qid of a Wikidata entity passed as |qid= -- It takes an optional parameter |wiki= to determine which wiki is to be checked for a sitelink -- If the parameter is blank, then it uses the local wiki. -- If there is a sitelink to an article available, it returns the plain text link to the article -- If there is no sitelink, it returns nil. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local _getSitelink = function(qid, wiki) qid = (qid or ""):upper() if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return nil end wiki = wiki or "" local sitelink if wiki == "" then sitelink = mw.wikibase.getSitelink(qid) else sitelink = mw.wikibase.getSitelink(qid, wiki) end return sitelink end ------------------------------------------------------------------------------- -- _getCommonslink takes an optional qid of a Wikidata entity passed as |qid= -- It returns one of the following in order of preference: -- the Commons sitelink of the Wikidata entity - but not if onlycat=true and it's not a category; -- the Commons sitelink of the topic's main category of the Wikidata entity; -- the Commons category of the Wikidata entity - unless fallback=false. ------------------------------------------------------------------------------- -- Dependencies: _getSitelink(); parseParam() ------------------------------------------------------------------------------- local _getCommonslink = function(qid, onlycat, fallback) qid = (qid or ""):upper() if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return nil end onlycat = parseParam(onlycat, false) if fallback == "" then fallback = nil end local sitelink = _getSitelink(qid, "commonswiki") if onlycat and sitelink and sitelink:sub(1,9) ~= "Category:" then sitelink = nil end if not sitelink then -- check for topic's main category local prop910 = mw.wikibase.getBestStatements(qid, "P910")[1] if prop910 then local tmcid = prop910.mainsnak.datavalue and prop910.mainsnak.datavalue.value.id sitelink = _getSitelink(tmcid, "commonswiki") end if not sitelink then -- check for list's main category local prop1754 = mw.wikibase.getBestStatements(qid, "P1754")[1] if prop1754 then local tmcid = prop1754.mainsnak.datavalue and prop1754.mainsnak.datavalue.value.id sitelink = _getSitelink(tmcid, "commonswiki") end end end if not sitelink and fallback then -- check for Commons category (string value) local prop373 = mw.wikibase.getBestStatements(qid, "P373")[1] if prop373 then sitelink = prop373.mainsnak.datavalue and prop373.mainsnak.datavalue.value if sitelink then sitelink = "Category:" .. sitelink end end end return sitelink end ------------------------------------------------------------------------------- -- The label in a Wikidata item is subject to vulnerabilities -- that an attacker might try to exploit. -- It needs to be 'sanitised' by removing any wikitext before use. -- If it doesn't exist, return the id for the item -- a second (boolean) value is also returned, value is true when the label exists ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local labelOrId = function(id, lang) if lang == "default" then lang = findLang().code end local label if lang then label = mw.wikibase.getLabelByLang(id, lang) else label = mw.wikibase.getLabel(id) end if label then return mw.text.nowiki(label), true else return id, false end end ------------------------------------------------------------------------------- -- linkedItem takes an entity-id and returns a string, linked if possible. -- This is the handler for "wikibase-item". Preferences: -- 1. Display linked disambiguated sitelink if it exists -- 2. Display linked label if it is a redirect -- 3. TBA: Display an inter-language link for the label if it exists other than in default language -- 4. Display unlinked label if it exists -- 5. Display entity-id for now to indicate a label could be provided -- dtxt is text to be used instead of label, or nil. -- shortname is boolean switch to use P1813 (short name) instead of label if true. -- lang is the current language code. -- uselbl is boolean switch to force display of the label instead of the sitelink (default: false) -- linkredir is boolean switch to allow linking to a redirect (default: false) -- formatvalue is boolean switch to allow formatting as italics or quoted (default: false) ------------------------------------------------------------------------------- -- Dependencies: labelOrId(); donotlink[] ------------------------------------------------------------------------------- local linkedItem = function(id, args) local lprefix = (args.lp or args.lprefix or args.linkprefix or ""):gsub('"', '') -- toughen against nil values passed local lpostfix = (args.lpostfix or ""):gsub('"', '') local prefix = (args.prefix or ""):gsub('"', '') local postfix = (args.postfix or ""):gsub('"', '') local dtxt = args.dtxt local shortname = args.shortname local lang = args.lang or "en" -- fallback to default if missing local uselbl = args.uselabel or args.uselbl uselbl = parseParam(uselbl, false) local linkredir = args.linkredir linkredir = parseParam(linkredir, false) local formatvalue = args.formatvalue or args.fv formatvalue = parseParam(formatvalue, false) -- see if item might need italics or quotes local fmt = "" if next(formats) and formatvalue then for k, v in ipairs( mw.wikibase.getBestStatements(id, "P31") ) do if v.mainsnak.datavalue and formats[v.mainsnak.datavalue.value.id] then fmt = formats[v.mainsnak.datavalue.value.id] break -- pick the first match end end end local disp local sitelink = mw.wikibase.getSitelink(id) local label, islabel if dtxt then label, islabel = dtxt, true elseif shortname then -- see if there is a shortname in our language, and set label to it for k, v in ipairs( mw.wikibase.getBestStatements(id, "P1813") ) do if v.mainsnak.datavalue.value.language == lang then label, islabel = v.mainsnak.datavalue.value.text, true break end -- test for language match end -- loop through values of short name -- if we have no label set, then there was no shortname available if not islabel then label, islabel = labelOrId(id) shortname = false end else label, islabel = labelOrId(id) end if mw.site.siteName ~= "Wikimedia Commons" then if sitelink then if not (dtxt or shortname) then -- if sitelink and label are the same except for case, no need to process further if sitelink:lower() ~= label:lower() then -- strip any namespace or dab from the sitelink local pos = sitelink:find(":") or 0 local slink = sitelink if pos > 0 then local pfx = sitelink:sub(1,pos-1) if mw.site.namespaces[pfx] then -- that prefix is a valid namespace, so remove it slink = sitelink:sub(pos+1) end end -- remove stuff after commas or inside parentheses - ie. dabs slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "") -- if uselbl is false, use sitelink instead of label if not uselbl then -- use slink as display, preserving label case - find("^%u") is true for 1st char uppercase if label:find("^%u") then label = slink:gsub("^(%l)", string.upper) else label = slink:gsub("^(%u)", string.lower) end end end end if donotlink[label] then disp = prefix .. fmt .. label .. fmt .. postfix else disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]" end elseif islabel then -- no sitelink, label exists, so check if a redirect with that title exists, if linkredir is true -- display plain label by default disp = prefix .. fmt .. label .. fmt .. postfix if linkredir then local artitle = mw.title.new(label, 0) -- only nil if label has invalid chars if not donotlink[label] and artitle and artitle.redirectTarget then -- there's a redirect with the same title as the label, so let's link to that disp = "[[".. lprefix .. label .. lpostfix .. "|" .. prefix .. fmt .. label .. fmt .. postfix .. "]]" end end -- test if article title exists as redirect on current Wiki else -- no sitelink and no label, so return whatever was returned from labelOrId for now -- add tracking category [[Category:Articles with missing Wikidata information]] -- for enwiki, just return the tracking category if mw.wikibase.getGlobalSiteId() == "enwiki" then disp = i18n.missinginfocat else disp = prefix .. label .. postfix .. i18n.missinginfocat end end else local ccat = mw.wikibase.getBestStatements(id, "P373")[1] if ccat and ccat.mainsnak.datavalue then ccat = ccat.mainsnak.datavalue.value disp = "[[" .. lprefix .. "Category:" .. ccat .. lpostfix .. "|" .. prefix .. label .. postfix .. "]]" elseif sitelink then -- this asumes that if a sitelink exists, then a label also exists disp = "[[" .. lprefix .. sitelink .. lpostfix .. "|" .. prefix .. label .. postfix .. "]]" else -- no sitelink and no Commons cat, so return label from labelOrId for now disp = prefix .. label .. postfix end end return disp end ------------------------------------------------------------------------------- -- sourced takes a table representing a statement that may or may not have references -- it looks for a reference sourced to something not containing the word "wikipedia" -- it returns a boolean = true if it finds a sourced reference. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local sourced = function(claim) if claim.references then for kr, vr in pairs(claim.references) do local ref = mw.wikibase.renderSnaks(vr.snaks) if not ref:find("Wiki") then return true end end end end ------------------------------------------------------------------------------- -- setRanks takes a flag (parameter passed) that requests the values to return -- "b[est]" returns preferred if available, otherwise normal -- "p[referred]" returns preferred -- "n[ormal]" returns normal -- "d[eprecated]" returns deprecated -- multiple values are allowed, e.g. "preferred normal" (which is the default) -- "best" will override the other flags, and set p and n ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local setRanks = function(rank) rank = (rank or ""):lower() -- if nothing passed, return preferred and normal -- if rank == "" then rank = "p n" end local ranks = {} for w in string.gmatch(rank, "%a+") do w = w:sub(1,1) if w == "b" or w == "p" or w == "n" or w == "d" then ranks[w] = true end end -- check if "best" is requested or no ranks requested; and if so, set preferred and normal if ranks.b or not next(ranks) then ranks.p = true ranks.n = true end return ranks end ------------------------------------------------------------------------------- -- parseInput processes the Q-id , the blacklist and the whitelist -- if an input parameter is supplied, it returns that and ends the call. -- it returns (1) either the qid or nil indicating whether or not the call should continue -- and (2) a table containing all of the statements for the propertyID and relevant Qid -- if "best" ranks are requested, it returns those instead of all non-deprecated ranks ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- local parseInput = function(frame, input_parm, property_id) -- There may be a local parameter supplied, if it's blank, set it to nil input_parm = mw.text.trim(input_parm or "") if input_parm == "" then input_parm = nil end -- return nil if Wikidata is not available if not mw.wikibase then return false, input_parm end local args = frame.args -- can take a named parameter |qid which is the Wikidata ID for the article. -- if it's not supplied, use the id for the current page local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end -- if there's no Wikidata item for the current page return nil if not qid then return false, input_parm end -- The blacklist is passed in named parameter |suppressfields local blacklist = args.suppressfields or args.spf or "" -- The whitelist is passed in named parameter |fetchwikidata local whitelist = args.fetchwikidata or args.fwd or "" if whitelist == "" then whitelist = "NONE" end -- The name of the field that this function is called from is passed in named parameter |name local fieldname = args.name or "" if blacklist ~= "" then -- The name is compulsory when blacklist is used, so return nil if it is not supplied if fieldname == "" then return false, nil end -- If this field is on the blacklist, then return nil if blacklist:find(fieldname) then return false, nil end end -- If we got this far then we're not on the blacklist -- The blacklist overrides any locally supplied parameter as well -- If a non-blank input parameter was supplied return it if input_parm then return false, input_parm end -- We can filter out non-valid properties if property_id:sub(1,1):upper() ~="P" or property_id == "P0" then return false, nil end -- Otherwise see if this field is on the whitelist: -- needs a bit more logic because find will return its second value = 0 if fieldname is "" -- but nil if fieldname not found on whitelist local _, found = whitelist:find(fieldname) found = ((found or 0) > 0) if whitelist ~= 'ALL' and (whitelist:upper() == "NONE" or not found) then return false, nil end -- See what's on Wikidata (the call always returns a table, but it may be empty): local props = {} if args.reqranks.b then props = mw.wikibase.getBestStatements(qid, property_id) else props = mw.wikibase.getAllStatements(qid, property_id) end if props[1] then return qid, props end -- no property on Wikidata return false, nil end ------------------------------------------------------------------------------- -- createicon assembles the "Edit at Wikidata" pen icon. -- It returns a wikitext string inside a span class="penicon" -- if entityID is nil or empty, the ID associated with current page is used -- langcode and propertyID may be nil or empty ------------------------------------------------------------------------------- -- Dependencies: i18n[]; ------------------------------------------------------------------------------- local createicon = function(langcode, entityID, propertyID) langcode = langcode or "" if not entityID or entityID == "" then entityID= mw.wikibase.getEntityIdForCurrentPage() end propertyID = propertyID or "" local icon = "&nbsp;<span class='penicon autoconfirmed-show'>[[" -- "&nbsp;<span data-bridge-edit-flow='overwrite' class='penicon'>[[" -> enable Wikidata Bridge .. i18n["filespace"] .. ":OOjs UI icon edit-ltr-progressive.svg |frameless |text-top |10px |alt=" .. i18n["editonwikidata"] .. "|link=https://www.wikidata.org/wiki/" .. entityID if langcode ~= "" then icon = icon .. "?uselang=" .. langcode end if propertyID ~= "" then icon = icon .. "#" .. propertyID end icon = icon .. "|" .. i18n["editonwikidata"] .. "]]</span>" return icon end ------------------------------------------------------------------------------- -- assembleoutput takes the sequence table containing the property values -- and formats it according to switches given. It returns a string or nil. -- It uses the entityID (and optionally propertyID) to create a link in the pen icon. ------------------------------------------------------------------------------- -- Dependencies: parseParam(); ------------------------------------------------------------------------------- local assembleoutput = function(out, args, entityID, propertyID) -- sorted is a boolean passed to enable sorting of the values returned -- if nothing or an empty string is passed set it false -- if "false" or "no" or "0" is passed set it false local sorted = parseParam(args.sorted, false) -- noicon is a boolean passed to suppress the trailing "edit at Wikidata" icon -- for use when the value is processed further by the infobox -- if nothing or an empty string is passed set it false -- if "false" or "no" or "0" is passed set it false local noic = parseParam(args.noicon, false) -- list is the name of a template that a list of multiple values is passed through -- examples include "hlist" and "ubl" -- setting it to "prose" produces something like "1, 2, 3, and 4" local list = args.list or "" -- sep is a string that is used to separate multiple returned values -- if nothing or an empty string is passed set it to the default -- any double-quotes " are stripped out, so that spaces may be passed -- e.g. |sep=" - " local sepdefault = i18n["list separator"] local separator = args.sep or "" separator = string.gsub(separator, '"', '') if separator == "" then separator = sepdefault end -- collapse is a number that determines the maximum number of returned values -- before the output is collapsed. -- Zero or not a number result in no collapsing (default becomes 0). local collapse = tonumber(args.collapse) or 0 -- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value -- this is useful for tracking and debugging local replacetext = mw.text.trim(args.rt or args.replacetext or "") -- if there's anything to return, then return a list -- comma-separated by default, but may be specified by the sep parameter -- optionally specify a hlist or ubl or a prose list, etc. local strout if #out > 0 then if sorted then table.sort(out) end -- if there's something to display and a pen icon is wanted, add it the end of the last value local hasdisplay = false for i, v in ipairs(out) do if v ~= i18n.missinginfocat then hasdisplay = true break end end if not noic and hasdisplay then out[#out] = out[#out] .. createicon(args.langobj.code, entityID, propertyID) end if list == "" then strout = table.concat(out, separator) elseif list:lower() == "prose" then strout = mw.text.listToText( out ) else strout = mw.getCurrentFrame():expandTemplate{title = list, args = out} end if collapse >0 and #out > collapse then strout = collapsediv .. strout .. "</div>" end else strout = nil -- no items had valid reference end if replacetext ~= "" and strout then strout = replacetext end return strout end ------------------------------------------------------------------------------- -- rendersnak takes a table (propval) containing the information stored on one property value -- and returns the value as a string and its language if monolingual text. -- It handles data of type: -- wikibase-item -- time -- string, url, commonsMedia, external-id -- quantity -- globe-coordinate -- monolingualtext -- It also requires linked, the link/pre/postfixes, uabbr, and the arguments passed from frame. -- The optional filter parameter allows quantities to be be filtered by unit Qid. ------------------------------------------------------------------------------- -- Dependencies: parseParam(); labelOrId(); i18n[]; dateFormat(); -- roundto(); decimalPrecision(); decimalToDMS(); linkedItem(); ------------------------------------------------------------------------------- local rendersnak = function(propval, args, linked, lpre, lpost, pre, post, uabbr, filter) lpre = lpre or "" lpost = lpost or "" pre = pre or "" post = post or "" args.lang = args.lang or findLang().code -- allow values to display a fixed text instead of label local dtxt = args.displaytext or args.dt if dtxt == "" then dtxt = nil end -- switch to use display of short name (P1813) instead of label local shortname = args.shortname or args.sn shortname = parseParam(shortname, false) local snak = propval.mainsnak or propval local dtype = snak.datatype local dv = snak.datavalue dv = dv and dv.value -- value and monolingual text language code returned local val, mlt if propval.rank and not args.reqranks[propval.rank:sub(1, 1)] then -- val is nil: value has a rank that isn't requested ------------------------------------ elseif snak.snaktype == "somevalue" then -- value is unknown val = i18n["Unknown"] ------------------------------------ elseif snak.snaktype == "novalue" then -- value is none -- val = "No value" -- don't return anything ------------------------------------ elseif dtype == "wikibase-item" then -- data type is a wikibase item: -- it's wiki-linked value, so output as link if enabled and possible local qnumber = dv.id if linked then val = linkedItem(qnumber, args) else -- no link wanted so check for display-text, otherwise test for lang code local label, islabel if dtxt then label = dtxt else label, islabel = labelOrId(qnumber) local langlabel = mw.wikibase.getLabelByLang(qnumber, args.lang) if langlabel then label = mw.text.nowiki( langlabel ) end end val = pre .. label .. post end -- test for link required ------------------------------------ elseif dtype == "time" then -- data type is time: -- time is in timestamp format -- date precision is integer per mediawiki -- output formatting according to preferences (y/dmy/mdy) -- BC format as BC or BCE -- plaindate is passed to disable looking for "sourcing cirumstances" -- or to set the adjectival form -- qualifiers (if any) is a nested table or nil -- lang is given, or user language, or site language -- -- Here we can check whether args.df has a value -- If not, use code from Module:Sandbox/RexxS/Getdateformat to set it from templates like {{Use mdy dates}} val = dateFormat(dv.time, dv.precision, args.df, args.bc, args.pd, propval.qualifiers, args.lang, "", dv.calendarmodel) ------------------------------------ -- data types which are strings: elseif dtype == "commonsMedia" or dtype == "external-id" or dtype == "string" or dtype == "url" then -- commonsMedia or external-id or string or url -- all have mainsnak.datavalue.value as string if (lpre == "" or lpre == ":") and lpost == "" then -- don't link if no linkpre/postfix or linkprefix is just ":" val = pre .. dv .. post elseif dtype == "external-id" then val = "[" .. lpre .. dv .. lpost .. " " .. pre .. dv .. post .. "]" else val = "[[" .. lpre .. dv .. lpost .. "|" .. pre .. dv .. post .. "]]" end -- check for link requested (i.e. either linkprefix or linkpostfix exists) ------------------------------------ -- data types which are quantities: elseif dtype == "quantity" then -- quantities have mainsnak.datavalue.value.amount and mainsnak.datavalue.value.unit -- the unit is of the form http://www.wikidata.org/entity/Q829073 -- -- implement a switch to turn on/off numerical formatting later local fnum = true -- -- a switch to turn on/off conversions - only for en-wiki local conv = parseParam(args.conv or args.convert, false) -- if we have conversions, we won't have formatted numbers or scales if conv then uabbr = true fnum = false args.scale = "0" end -- -- a switch to turn on/off showing units, default is true local showunits = parseParam(args.su or args.showunits, true) -- -- convert amount to a number local amount = tonumber(dv.amount) or i18n["NaN"] -- -- scale factor for millions, billions, etc. local sc = tostring(args.scale or ""):sub(1,1):lower() local scale if sc == "a" then -- automatic scaling if amount > 1e15 then scale = 12 elseif amount > 1e12 then scale = 9 elseif amount > 1e9 then scale = 6 elseif amount > 1e6 then scale = 3 else scale = 0 end else scale = tonumber(args.scale) or 0 if scale < 0 or scale > 12 then scale = 0 end scale = math.floor(scale/3) * 3 end local factor = 10^scale amount = amount / factor -- ranges: local range = "" -- check if upper and/or lower bounds are given and significant local upb = tonumber(dv.upperBound) local lowb = tonumber(dv.lowerBound) if upb and lowb then -- differences rounded to 2 sig fig: local posdif = roundto(upb - amount, 2) / factor local negdif = roundto(amount - lowb, 2) / factor upb, lowb = amount + posdif, amount - negdif -- round scaled numbers to integers or 4 sig fig if (scale > 0 or sc == "a") then if amount < 1e4 then amount = roundto(amount, 4) else amount = math.floor(amount + 0.5) end end if fnum then amount = args.langobj:formatNum( amount ) end if posdif ~= negdif then -- non-symmetrical range = " +" .. posdif .. " -" .. negdif elseif posdif ~= 0 then -- symmetrical and non-zero range = " ±" .. posdif else -- otherwise range is zero, so leave it as "" end else -- round scaled numbers to integers or 4 sig fig if (scale > 0 or sc == "a") then if amount < 1e4 then amount = roundto(amount, 4) else amount = math.floor(amount + 0.5) end end if fnum then amount = args.langobj:formatNum( amount ) end end -- unit names and symbols: -- extract the qid in the form 'Qnnn' from the value.unit url -- and then fetch the label from that - or symbol if unitabbr is true local unit = "" local usep = "" local usym = "" local unitqid = string.match( dv.unit, "(Q%d+)" ) if filter and unitqid ~= filter then return nil end if unitqid and showunits then local uname = mw.wikibase.getLabelByLang(unitqid, args.lang) or "" if uname ~= "" then usep, unit = " ", uname end if uabbr then -- see if there's a unit symbol (P5061) local unitsymbols = mw.wikibase.getBestStatements(unitqid, "P5061") -- construct fallback table, add local lang and multiple languages local fbtbl = mw.language.getFallbacksFor( args.lang ) table.insert( fbtbl, 1, args.lang ) table.insert( fbtbl, 1, "mul" ) local found = false for idx1, us in ipairs(unitsymbols) do for idx2, fblang in ipairs(fbtbl) do if us.mainsnak.datavalue.value.language == fblang then usym = us.mainsnak.datavalue.value.text found = true break end if found then break end end -- loop through fallback table end -- loop through values of P5061 if found then usep, unit = "&nbsp;", usym end end end -- format display: if conv then if range == "" then val = mw.getCurrentFrame():expandTemplate{title = "cvt", args = {amount, unit}} else val = mw.getCurrentFrame():expandTemplate{title = "cvt", args = {lowb, "to", upb, unit}} end elseif unit == "$" or unit == "£" then val = unit .. amount .. range .. i18n.multipliers[scale] else val = amount .. range .. i18n.multipliers[scale] .. usep .. unit end ------------------------------------ -- datatypes which are global coordinates: elseif dtype == "globe-coordinate" then -- 'display' parameter defaults to "inline, title" *** unused for now *** -- local disp = args.display or "" -- if disp == "" then disp = "inline, title" end -- -- format parameter switches from deg/min/sec to decimal degrees -- default is deg/min/sec -- decimal degrees needs |format = dec local form = (args.format or ""):lower():sub(1,3) if form ~= "dec" then form = "dms" end -- not needed for now -- -- show parameter allows just the latitude, or just the longitude, or both -- to be returned as a signed decimal, ignoring the format parameter. local show = (args.show or ""):lower() if show ~= "longlat" then show = show:sub(1,3) end -- local lat, long, prec = dv.latitude, dv.longitude, dv.precision if show == "lat" then val = decimalPrecision(lat, prec) elseif show == "lon" then val = decimalPrecision(long, prec) elseif show == "longlat" then val = decimalPrecision(long, prec) .. ", " .. decimalPrecision(lat, prec) else local ns = "N" local ew = "E" if lat < 0 then ns = "S" lat = - lat end if long < 0 then ew = "W" long = - long end if form == "dec" then lat = decimalPrecision(lat, prec) long = decimalPrecision(long, prec) val = lat .. "°" .. ns .. " " .. long .. "°" .. ew else local latdeg, latmin, latsec = decimalToDMS(lat, prec) local longdeg, longmin, longsec = decimalToDMS(long, prec) if latsec == 0 and longsec == 0 then if latmin == 0 and longmin == 0 then val = latdeg .. "°" .. ns .. " " .. longdeg .. "°" .. ew else val = latdeg .. "°" .. latmin .. "′" .. ns .. " " val = val .. longdeg .. "°".. longmin .. "′" .. ew end else val = latdeg .. "°" .. latmin .. "′" .. latsec .. "″" .. ns .. " " val = val .. longdeg .. "°" .. longmin .. "′" .. longsec .. "″" .. ew end end end ------------------------------------ elseif dtype == "monolingualtext" then -- data type is Monolingual text: -- has mainsnak.datavalue.value as a table containing language/text pairs -- collect all the values in 'out' and languages in 'mlt' and process them later val = pre .. dv.text .. post mlt = dv.language ------------------------------------ else -- some other data type so write a specific handler val = "unknown data type: " .. dtype end -- of datatype/unknown value/sourced check return val, mlt end ------------------------------------------------------------------------------- -- propertyvalueandquals takes a property object, the arguments passed from frame, -- and a qualifier propertyID. -- It returns a sequence (table) of values representing the values of that property -- and qualifiers that match the qualifierID if supplied. ------------------------------------------------------------------------------- -- Dependencies: parseParam(); sourced(); labelOrId(); i18n.latestdatequalifier(); format_Date(); -- makeOrdinal(); roundto(); decimalPrecision(); decimalToDMS(); assembleoutput(); ------------------------------------------------------------------------------- local function propertyvalueandquals(objproperty, args, qualID) -- needs this style of declaration because it's re-entrant -- onlysourced is a boolean passed to return only values sourced to other than Wikipedia -- if nothing or an empty string is passed set it true local onlysrc = parseParam(args.onlysourced or args.osd, true) -- linked is a a boolean that enables the link to a local page via sitelink -- if nothing or an empty string is passed set it true local linked = parseParam(args.linked, true) -- prefix is a string that may be nil, empty (""), or a string of characters -- this is prefixed to each value -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local prefix = (args.prefix or ""):gsub('"', '') -- postfix is a string that may be nil, empty (""), or a string of characters -- this is postfixed to each value -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local postfix = (args.postfix or ""):gsub('"', '') -- linkprefix is a string that may be nil, empty (""), or a string of characters -- this creates a link and is then prefixed to each value -- useful when when multiple values are returned and indirect links are needed -- any double-quotes " are stripped out, so that spaces may be passed local lprefix = (args.linkprefix or args.lp or ""):gsub('"', '') -- linkpostfix is a string that may be nil, empty (""), or a string of characters -- this is postfixed to each value when linking is enabled with lprefix -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local lpostfix = (args.linkpostfix or ""):gsub('"', '') -- wdlinks is a boolean passed to enable links to Wikidata when no article exists -- if nothing or an empty string is passed set it false local wdl = parseParam(args.wdlinks or args.wdl, false) -- unitabbr is a boolean passed to enable unit abbreviations for common units -- if nothing or an empty string is passed set it false local uabbr = parseParam(args.unitabbr or args.uabbr, false) -- qualsonly is a boolean passed to return just the qualifiers -- if nothing or an empty string is passed set it false local qualsonly = parseParam(args.qualsonly or args.qo, false) -- maxvals is a string that may be nil, empty (""), or a number -- this determines how many items may be returned when multiple values are available -- setting it = 1 is useful where the returned string is used within another call, e.g. image local maxvals = tonumber(args.maxvals) or 0 -- pd (plain date) is a string: yes/true/1 | no/false/0 | adj -- to disable/enable "sourcing cirumstances" or use adjectival form for the plain date local pd = args.plaindate or args.pd or "no" args.pd = pd -- allow qualifiers to have a different date format; default to year unless qualsonly is set args.qdf = args.qdf or args.qualifierdateformat or args.df or (not qualsonly and "y") local lang = args.lang or findLang().code -- qualID is a string list of wanted qualifiers or "ALL" qualID = qualID or "" -- capitalise list of wanted qualifiers and substitute "DATES" qualID = qualID:upper():gsub("DATES", "P580, P582") local allflag = (qualID == "ALL") -- create table of wanted qualifiers as key local qwanted = {} -- create sequence of wanted qualifiers local qorder = {} for q in mw.text.gsplit(qualID, "%p") do -- split at punctuation and iterate local qtrim = mw.text.trim(q) if qtrim ~= "" then qwanted[mw.text.trim(q)] = true qorder[#qorder+1] = qtrim end end -- qsep is the output separator for rendering qualifier list local qsep = (args.qsep or ""):gsub('"', '') -- qargs are the arguments to supply to assembleoutput() local qargs = { ["osd"] = "false", ["linked"] = tostring(linked), ["prefix"] = args.qprefix, ["postfix"] = args.qpostfix, ["linkprefix"] = args.qlinkprefix or args.qlp, ["linkpostfix"] = args.qlinkpostfix, ["wdl"] = "false", ["unitabbr"] = tostring(uabbr), ["maxvals"] = 0, ["sorted"] = tostring(args.qsorted), ["noicon"] = "true", ["list"] = args.qlist, ["sep"] = qsep, ["langobj"] = args.langobj, ["lang"] = args.langobj.code, ["df"] = args.qdf, ["sn"] = parseParam(args.qsn or args.qshortname, false), } -- all proper values of a Wikidata property will be the same type as the first -- qualifiers don't have a mainsnak, properties do local datatype = objproperty[1].datatype or objproperty[1].mainsnak.datatype -- out[] holds the a list of returned values for this property -- mlt[] holds the language code if the datatype is monolingual text local out = {} local mlt = {} for k, v in ipairs(objproperty) do local hasvalue = true if (onlysrc and not sourced(v)) then -- no value: it isn't sourced when onlysourced=true hasvalue = false else local val, lcode = rendersnak(v, args, linked, lprefix, lpostfix, prefix, postfix, uabbr) if not val then hasvalue = false -- rank doesn't match elseif qualsonly and qualID then -- suppress value returned: only qualifiers are requested else out[#out+1], mlt[#out+1] = val, lcode end end -- See if qualifiers are to be returned: local snak = v.mainsnak or v if hasvalue and v.qualifiers and qualID ~= "" and snak.snaktype~="novalue" then -- collect all wanted qualifier values returned in qlist, indexed by propertyID local qlist = {} local timestart, timeend = "", "" -- loop through qualifiers for k1, v1 in pairs(v.qualifiers) do if allflag or qwanted[k1] then if k1 == "P1326" then local ts = v1[1].datavalue.value.time local dp = v1[1].datavalue.value.precision qlist[k1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "before") elseif k1 == "P1319" then local ts = v1[1].datavalue.value.time local dp = v1[1].datavalue.value.precision qlist[k1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "after") elseif k1 == "P580" then timestart = propertyvalueandquals(v1, qargs)[1] or "" -- treat only one start time as valid elseif k1 == "P582" then timeend = propertyvalueandquals(v1, qargs)[1] or "" -- treat only one end time as valid else local q = assembleoutput(propertyvalueandquals(v1, qargs), qargs) -- we already deal with circa via 'sourcing circumstances' if the datatype was time -- circa may be either linked or unlinked *** internationalise later *** if datatype ~= "time" or q ~= "circa" and not (type(q) == "string" and q:find("circa]]")) then qlist[k1] = q end end end -- of test for wanted end -- of loop through qualifiers -- set date separator local t = timestart .. timeend -- *** internationalise date separators later *** local dsep = "&ndash;" if t:find("%s") or t:find("&nbsp;") then dsep = " &ndash; " end -- set the order for the list of qualifiers returned; start time and end time go last if next(qlist) then local qlistout = {} if allflag then for k2, v2 in pairs(qlist) do qlistout[#qlistout+1] = v2 end else for i2, v2 in ipairs(qorder) do qlistout[#qlistout+1] = qlist[v2] end end if t ~= "" then qlistout[#qlistout+1] = timestart .. dsep .. timeend end local qstr = assembleoutput(qlistout, qargs) if qualsonly then out[#out+1] = qstr else out[#out] = out[#out] .. " (" .. qstr .. ")" end elseif t ~= "" then if qualsonly then if timestart == "" then out[#out+1] = timeend elseif timeend == "" then out[#out+1] = timestart else out[#out+1] = timestart .. dsep .. timeend end else out[#out] = out[#out] .. " (" .. timestart .. dsep .. timeend .. ")" end end end -- of test for qualifiers wanted if maxvals > 0 and #out >= maxvals then break end end -- of for each value loop -- we need to pick one value to return if the datatype was "monolingualtext" -- if there's only one value, use that -- otherwise look through the fallback languages for a match if datatype == "monolingualtext" and #out >1 then lang = mw.text.split( lang, '-', true )[1] local fbtbl = mw.language.getFallbacksFor( lang ) table.insert( fbtbl, 1, lang ) local bestval = "" local found = false for idx1, lang1 in ipairs(fbtbl) do for idx2, lang2 in ipairs(mlt) do if (lang1 == lang2) and not found then bestval = out[idx2] found = true break end end -- loop through values of property end -- loop through fallback languages if found then -- replace output table with a table containing the best value out = { bestval } else -- more than one value and none of them on the list of fallback languages -- sod it, just give them the first one out = { out[1] } end end return out end ------------------------------------------------------------------------------- -- Common code for p.getValueByQual and p.getValueByLang ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; assembleoutput; ------------------------------------------------------------------------------- local _getvaluebyqual = function(frame, qualID, checkvalue) -- The property ID that will have a qualifier is the first unnamed parameter local propertyID = mw.text.trim(frame.args[1] or "") if propertyID == "" then return "no property supplied" end if qualID == "" then return "no qualifier supplied" end -- onlysourced is a boolean passed to return property values -- only when property values are sourced to something other than Wikipedia -- if nothing or an empty string is passed set it true -- if "false" or "no" or 0 is passed set it false local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) -- set the requested ranks flags frame.args.reqranks = setRanks(frame.args.rank) -- set a language object and code in the frame.args table frame.args.langobj = findLang(frame.args.lang) frame.args.lang = frame.args.langobj.code local args = frame.args -- check for locally supplied parameter in second unnamed parameter -- success means no local parameter and the property exists local qid, props = parseInput(frame, args[2], propertyID) local linked = parseParam(args.linked, true) local lpre = (args.linkprefix or args.lp or ""):gsub('"', '') local lpost = (args.linkpostfix or ""):gsub('"', '') local pre = (args.prefix or ""):gsub('"', '') local post = (args.postfix or ""):gsub('"', '') local uabbr = parseParam(args.unitabbr or args.uabbr, false) local filter = (args.unit or ""):upper() local maxvals = tonumber(args.maxvals) or 0 if filter == "" then filter = nil end if qid then local out = {} -- Scan through the values of the property -- we want something like property is "pronunciation audio (P443)" in propertyID -- with a qualifier like "language of work or name (P407)" in qualID -- whose value has the required ID, like "British English (Q7979)", in qval for k1, v1 in ipairs(props) do if v1.mainsnak.snaktype == "value" then -- check if it has the right qualifier local v1q = v1.qualifiers if v1q and v1q[qualID] then if onlysrc == false or sourced(v1) then -- if we've got this far, we have a (sourced) claim with qualifiers -- so see if matches the required value -- We'll only deal with wikibase-items and strings for now if v1q[qualID][1].datatype == "wikibase-item" then if checkvalue(v1q[qualID][1].datavalue.value.id) then out[#out + 1] = rendersnak(v1, args, linked, lpre, lpost, pre, post, uabbr, filter) end elseif v1q[qualID][1].datatype == "string" then if checkvalue(v1q[qualID][1].datavalue.value) then out[#out + 1] = rendersnak(v1, args, linked, lpre, lpost, pre, post, uabbr, filter) end end end -- of check for sourced end -- of check for matching required value and has qualifiers else return nil end -- of check for string if maxvals > 0 and #out >= maxvals then break end end -- of loop through values of propertyID return assembleoutput(out, frame.args, qid, propertyID) else return props -- either local parameter or nothing end -- of test for success return nil end ------------------------------------------------------------------------------- -- _location takes Q-id and follows P276 (location) -- or P131 (located in the administrative territorial entity) or P706 (located on terrain feature) -- from the initial item to higher level territories/locations until it reaches the highest. -- An optional boolean, 'first', determines whether the first item is returned (default: false). -- An optional boolean 'skip' toggles the display to skip to the last item (default: false). -- It returns a table containing the locations - linked where possible, except for the highest. ------------------------------------------------------------------------------- -- Dependencies: findLang(); labelOrId(); linkedItem ------------------------------------------------------------------------------- local _location = function(qid, first, skip) first = parseParam(first, false) skip = parseParam(skip, false) local locs = {"P276", "P131", "P706"} local out = {} local langcode = findLang():getCode() local finished = false local count = 0 local prevqid = "Q0" repeat local prop for i1, v1 in ipairs(locs) do local proptbl = mw.wikibase.getBestStatements(qid, v1) if #proptbl > 1 then -- there is more than one higher location local prevP131, prevP131id if prevqid ~= "Q0" then prevP131 = mw.wikibase.getBestStatements(prevqid, "P131")[1] prevP131id = prevP131 and prevP131.mainsnak.datavalue and prevP131.mainsnak.datavalue.value.id end for i2, v2 in ipairs(proptbl) do local parttbl = v2.qualifiers and v2.qualifiers.P518 if parttbl then -- this higher location has qualifier 'applies to part' (P518) for i3, v3 in ipairs(parttbl) do if v3.snaktype == "value" and v3.datavalue.value.id == prevqid then -- it has a value equal to the previous location prop = proptbl[i2] break end -- of test for matching last location end -- of loop through values of 'applies to part' else -- there's no qualifier 'applies to part' (P518) -- so check if the previous location had a P131 that matches this alternate if qid == prevP131id then prop = proptbl[i2] break end -- of test for matching previous P131 end end -- of loop through parent locations -- fallback to second value if match not found prop = prop or proptbl[2] elseif #proptbl > 0 then prop = proptbl[1] end if prop then break end end -- check if it's an instance of (P31) a country (Q6256) or sovereign state (Q3624078) -- and terminate the chain if it is local inst = mw.wikibase.getAllStatements(qid, "P31") if #inst > 0 then for k, v in ipairs(inst) do local instid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id -- stop if it's a country (or a country within the United Kingdom if skip is true) if instid == "Q6256" or instid == "Q3624078" or (skip and instid == "Q3336843") then prop = nil -- this will ensure this is treated as top-level location break end end end -- get the name of this location and update qid to point to the parent location if prop and prop.mainsnak.datavalue then if not skip or count == 0 then local args = { lprefix = ":" } out[#out+1] = linkedItem(qid, args) -- get a linked value if we can end qid, prevqid = prop.mainsnak.datavalue.value.id, qid else -- This is top-level location, so get short name except when this is the first item -- Use full label if there's no short name or this is the first item local prop1813 = mw.wikibase.getAllStatements(qid, "P1813") -- if there's a short name and this isn't the only item if prop1813[1] and (#out > 0)then local shortname -- short name is monolingual text, so look for match to the local language -- choose the shortest 'short name' in that language for k, v in pairs(prop1813) do if v.mainsnak.datavalue.value.language == langcode then local name = v.mainsnak.datavalue.value.text if (not shortname) or (#name < #shortname) then shortname = name end end end -- add the shortname if one is found, fallback to the label -- but skip it if it's "USA" if shortname ~= "USA" then out[#out+1] = shortname or labelOrId(qid) else if skip then out[#out+1] = "US" end end else -- no shortname, so just add the label local loc = labelOrId(qid) -- exceptions go here: if loc == "United States of America" then out[#out+1] = "United States" else out[#out+1] = loc end end finished = true end count = count + 1 until finished or count >= 10 -- limit to 10 levels to avoid infinite loops -- remove the first location if not required if not first then table.remove(out, 1) end -- we might have duplicate text for consecutive locations, so remove them if #out > 2 then local plain = {} for i, v in ipairs(out) do -- strip any links plain[i] = v:gsub("^%[%[[^|]*|", ""):gsub("]]$", "") end local idx = 2 repeat if plain[idx] == plain[idx-1] then -- duplicate found local removeidx = 0 if (plain[idx] ~= out[idx]) and (plain[idx-1] == out[idx-1]) then -- only second one is linked, so drop the first removeidx = idx - 1 elseif (plain[idx] == out[idx]) and (plain[idx-1] ~= out[idx-1]) then -- only first one is linked, so drop the second removeidx = idx else -- pick one removeidx = idx - (os.time()%2) end table.remove(out, removeidx) table.remove(plain, removeidx) else idx = idx +1 end until idx >= #out end return out end ------------------------------------------------------------------------------- -- _getsumofparts scans the property 'has part' (P527) for values matching a list. -- The list (args.vlist) consists of a string of Qids separated by spaces or any usual punctuation. -- If the matched values have a qualifer 'quantity' (P1114), those quantites are summed. -- The sum is returned as a number (i.e. 0 if none) -- a table of arguments is supplied implementing the usual parameters. ------------------------------------------------------------------------------- -- Dependencies: setRanks; parseParam; parseInput; sourced; assembleoutput; ------------------------------------------------------------------------------- local _getsumofparts = function(args) local vallist = (args.vlist or ""):upper() if vallist == "" then return end args.reqranks = setRanks(args.rank) local f = {} f.args = args local qid, props = parseInput(f, "", "P527") if not qid then return 0 end local onlysrc = parseParam(args.onlysourced or args.osd, true) local sum = 0 for k1, v1 in ipairs(props) do if (onlysrc == false or sourced(v1)) and v1.mainsnak.snaktype == "value" and v1.mainsnak.datavalue.type == "wikibase-entityid" and vallist:match( v1.mainsnak.datavalue.value.id ) and v1.qualifiers then local quals = v1.qualifiers["P1114"] if quals then for k2, v2 in ipairs(quals) do sum = sum + v2.datavalue.value.amount end end end end return sum end ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- Public functions ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- _getValue makes the functionality of getValue available to other modules ------------------------------------------------------------------------------- -- Dependencies: setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced; -- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS; ------------------------------------------------------------------------------- p._getValue = function(args) -- parameter sets for commonly used groups of parameters local paraset = tonumber(args.ps or args.parameterset or 0) if paraset == 1 then -- a common setting args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" elseif paraset == 2 then -- equivalent to raw args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" args.linked = "no" args.pd = "true" elseif paraset == 3 then -- third set goes here end -- implement eid parameter local eid = args.eid if eid == "" then return nil elseif eid then args.qid = eid end local propertyID = mw.text.trim(args[1] or "") args.reqranks = setRanks(args.rank) -- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value -- this is useful for tracking and debugging, so we set fetchwikidata=ALL to fill the whitelist local replacetext = mw.text.trim(args.rt or args.replacetext or "") if replacetext ~= "" then args.fetchwikidata = "ALL" end local f = {} f.args = args local entityid, props = parseInput(f, f.args[2], propertyID) if not entityid then return props -- either the input parameter or nothing end -- qual is a string containing the property ID of the qualifier(s) to be returned -- if qual == "ALL" then all qualifiers returned -- if qual == "DATES" then qualifiers P580 (start time) and P582 (end time) returned -- if nothing or an empty string is passed set it nil -> no qualifiers returned local qualID = mw.text.trim(args.qual or ""):upper() if qualID == "" then qualID = nil end -- set a language object and code in the args table args.langobj = findLang(args.lang) args.lang = args.langobj.code -- table 'out' stores the return value(s): local out = propertyvalueandquals(props, args, qualID) -- format the table of values and return it as a string: return assembleoutput(out, args, entityid, propertyID) end ------------------------------------------------------------------------------- -- getValue is used to get the value(s) of a property -- The property ID is passed as the first unnamed parameter and is required. -- A locally supplied parameter may optionaly be supplied as the second unnamed parameter. -- The function will now also return qualifiers if parameter qual is supplied ------------------------------------------------------------------------------- -- Dependencies: _getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced; -- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS; ------------------------------------------------------------------------------- p.getValue = function(frame) local args= frame.args if not args[1] then args = frame:getParent().args if not args[1] then return i18n.errors["No property supplied"] end end return p._getValue(args) end ------------------------------------------------------------------------------- -- getPreferredValue is used to get a value, -- (or a comma separated list of them if multiple values exist). -- If preferred ranks are set, it will return those values, otherwise values with normal ranks -- now redundant to getValue with |rank=best ------------------------------------------------------------------------------- -- Dependencies: p.getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; -- parseParam; sourced; labelOrId; i18n.latestdatequalifier; format_Date; -- makeOrdinal; roundto; decimalPrecision; decimalToDMS; ------------------------------------------------------------------------------- p.getPreferredValue = function(frame) frame.args.rank = "best" return p.getValue(frame) end ------------------------------------------------------------------------------- -- getCoords is used to get coordinates for display in an infobox -- whitelist and blacklist are implemented -- optional 'display' parameter is allowed, defaults to nil - was "inline, title" ------------------------------------------------------------------------------- -- Dependencies: setRanks(); parseInput(); decimalPrecision(); ------------------------------------------------------------------------------- p.getCoords = function(frame) local propertyID = "P625" -- if there is a 'display' parameter supplied, use it -- otherwise default to nothing local disp = frame.args.display or "" if disp == "" then disp = nil -- default to not supplying display parameter, was "inline, title" end -- there may be a format parameter to switch from deg/min/sec to decimal degrees -- default is deg/min/sec -- decimal degrees needs |format = dec local form = (frame.args.format or ""):lower():sub(1,3) if form ~= "dec" then form = "dms" end -- just deal with best values frame.args.reqranks = setRanks("best") local qid, props = parseInput(frame, frame.args[1], propertyID) if not qid then return props -- either local parameter or nothing else local dv = props[1].mainsnak.datavalue.value local lat, long, prec = dv.latitude, dv.longitude, dv.precision lat = decimalPrecision(lat, prec) long = decimalPrecision(long, prec) local lat_long = { lat, long } lat_long["display"] = disp lat_long["format"] = form -- invoke template Coord with the values stored in the table return frame:expandTemplate{title = 'coord', args = lat_long} end end ------------------------------------------------------------------------------- -- getQualifierValue is used to get a formatted value of a qualifier -- -- The call needs: a property (the unnamed parameter or 1=) -- a target value for that property (pval=) -- a qualifier for that target value (qual=) -- The usual whitelisting and blacklisting of the property is implemented -- The boolean onlysourced= parameter can be set to return nothing -- when the property is unsourced (or only sourced to Wikipedia) ------------------------------------------------------------------------------- -- Dependencies: parseParam(); setRanks(); parseInput(); sourced(); -- propertyvalueandquals(); assembleoutput(); -- labelOrId(); i18n.latestdatequalifier(); format_Date(); -- findLang(); makeOrdinal(); roundto(); decimalPrecision(); decimalToDMS(); ------------------------------------------------------------------------------- p.getQualifierValue = function(frame) -- The property ID that will have a qualifier is the first unnamed parameter local propertyID = mw.text.trim(frame.args[1] or "") -- The value of the property we want to match whose qualifier value is to be returned -- is passed in named parameter |pval= local propvalue = frame.args.pval -- The property ID of the qualifier -- whose value is to be returned is passed in named parameter |qual= local qualifierID = frame.args.qual -- A filter can be set like this: filter=P642==Q22674854 local filter, fprop, fval local ftable = mw.text.split(frame.args.filter or "", "==") if ftable[2] then fprop = mw.text.trim(ftable[1]) fval = mw.text.trim(ftable[2]) filter = true end -- onlysourced is a boolean passed to return qualifiers -- only when property values are sourced to something other than Wikipedia -- if nothing or an empty string is passed set it true -- if "false" or "no" or 0 is passed set it false local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) -- set a language object and language code in the frame.args table frame.args.langobj = findLang(frame.args.lang) frame.args.lang = frame.args.langobj.code -- set the requested ranks flags frame.args.reqranks = setRanks(frame.args.rank) -- check for locally supplied parameter in second unnamed parameter -- success means no local parameter and the property exists local qid, props = parseInput(frame, frame.args[2], propertyID) if qid then local out = {} -- Scan through the values of the property -- we want something like property is P793, significant event (in propertyID) -- whose value is something like Q385378, construction (in propvalue) -- then we can return the value(s) of a qualifier such as P580, start time (in qualifierID) for k1, v1 in pairs(props) do if v1.mainsnak.snaktype == "value" and v1.mainsnak.datavalue.type == "wikibase-entityid" then -- It's a wiki-linked value, so check if it's the target (in propvalue) and if it has qualifiers if v1.mainsnak.datavalue.value.id == propvalue and v1.qualifiers then if onlysrc == false or sourced(v1) then -- if we've got this far, we have a (sourced) claim with qualifiers -- which matches the target, so apply the filter and find the value(s) of the qualifier we want if not filter or (v1.qualifiers[fprop] and v1.qualifiers[fprop][1].datavalue.value.id == fval) then local quals = v1.qualifiers[qualifierID] if quals then -- can't reference qualifer, so set onlysourced = "no" (args are strings, not boolean) local qargs = frame.args qargs.onlysourced = "no" local vals = propertyvalueandquals(quals, qargs, qid) for k, v in ipairs(vals) do out[#out + 1] = v end end end end -- of check for sourced end -- of check for matching required value and has qualifiers end -- of check for wikibase entity end -- of loop through values of propertyID return assembleoutput(out, frame.args, qid, propertyID) else return props -- either local parameter or nothing end -- of test for success return nil end ------------------------------------------------------------------------------- -- getSumOfParts scans the property 'has part' (P527) for values matching a list. -- The list is passed in parameter vlist. -- It consists of a string of Qids separated by spaces or any usual punctuation. -- If the matched values have a qualifier 'quantity' (P1114), those quantities are summed. -- The sum is returned as a number or nothing if zero. ------------------------------------------------------------------------------- -- Dependencies: _getsumofparts; ------------------------------------------------------------------------------- p.getSumOfParts = function(frame) local sum = _getsumofparts(frame.args) if sum == 0 then return end return sum end ------------------------------------------------------------------------------- -- getValueByQual gets the value of a property which has a qualifier with a given entity value -- The call needs: -- a property ID (the unnamed parameter or 1=Pxxx) -- the ID of a qualifier for that property (qualID=Pyyy) -- either the Wikibase-entity ID of a value for that qualifier (qvalue=Qzzz) -- or a string value for that qualifier (qvalue=abc123) -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented ------------------------------------------------------------------------------- -- Dependencies: _getvaluebyqual; parseParam; setRanks; parseInput; sourced; -- assembleoutput; ------------------------------------------------------------------------------- p.getValueByQual = function(frame) local qualID = frame.args.qualID -- The Q-id of the value for the qualifier we want to match is in named parameter |qvalue= local qval = frame.args.qvalue or "" if qval == "" then return "no qualifier value supplied" end local function checkQID(id) return id == qval end return _getvaluebyqual(frame, qualID, checkQID) end ------------------------------------------------------------------------------- -- getValueByLang gets the value of a property which has a qualifier P407 -- ("language of work or name") whose value has the given language code -- The call needs: -- a property ID (the unnamed parameter or 1=Pxxx) -- the MediaWiki language code to match the language (lang=xx[-yy]) -- (if no code is supplied, it uses the default language) -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented ------------------------------------------------------------------------------- -- Dependencies: _getvaluebyqual; parseParam; setRanks; parseInput; sourced; assembleoutput; ------------------------------------------------------------------------------- p.getValueByLang = function(frame) -- The language code for the qualifier we want to match is in named parameter |lang= local langcode = findLang(frame.args.lang).code local function checkLanguage(id) -- id should represent a language like "British English (Q7979)" -- it should have string property "Wikimedia language code (P424)" -- qlcode will be a table: local qlcode = mw.wikibase.getBestStatements(id, "P424") if (#qlcode > 0) and (qlcode[1].mainsnak.datavalue.value == langcode) then return true end end return _getvaluebyqual(frame, "P407", checkLanguage) end ------------------------------------------------------------------------------- -- getValueByRefSource gets the value of a property which has a reference "stated in" (P248) -- whose value has the given entity-ID. -- The call needs: -- a property ID (the unnamed parameter or 1=Pxxx) -- the entity ID of a value to match where the reference is stated in (match=Qzzz) -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p.getValueByRefSource = function(frame) -- The property ID that we want to check is the first unnamed parameter local propertyID = mw.text.trim(frame.args[1] or ""):upper() if propertyID == "" then return "no property supplied" end -- The Q-id of the value we want to match is in named parameter |qvalue= local qval = (frame.args.match or ""):upper() if qval == "" then qval = "Q21540096" end local unit = (frame.args.unit or ""):upper() if unit == "" then unit = "Q4917" end local onlysrc = parseParam(frame.args.onlysourced or frame.args.osd, true) -- set the requested ranks flags frame.args.reqranks = setRanks(frame.args.rank) -- set a language object and code in the frame.args table frame.args.langobj = findLang(frame.args.lang) frame.args.lang = frame.args.langobj.code local linked = parseParam(frame.args.linked, true) local uabbr = parseParam(frame.args.uabbr or frame.args.unitabbr, false) -- qid not nil means no local parameter and the property exists local qid, props = parseInput(frame, frame.args[2], propertyID) if qid then local out = {} local mlt= {} for k1, v1 in ipairs(props) do if onlysrc == false or sourced(v1) then if v1.references then for k2, v2 in ipairs(v1.references) do if v2.snaks.P248 then for k3, v3 in ipairs(v2.snaks.P248) do if v3.datavalue.value.id == qval then out[#out+1], mlt[#out+1] = rendersnak(v1, frame.args, linked, "", "", "", "", uabbr, unit) if not mlt[#out] then -- we only need one match per property value -- unless datatype was monolingual text break end end -- of test for match end -- of loop through values "stated in" end -- of test that "stated in" exists end -- of loop through references end -- of test that references exist end -- of test for sourced end -- of loop through values of propertyID if #mlt > 0 then local langcode = frame.args.lang langcode = mw.text.split( langcode, '-', true )[1] local fbtbl = mw.language.getFallbacksFor( langcode ) table.insert( fbtbl, 1, langcode ) local bestval = "" local found = false for idx1, lang1 in ipairs(fbtbl) do for idx2, lang2 in ipairs(mlt) do if (lang1 == lang2) and not found then bestval = out[idx2] found = true break end end -- loop through values of property end -- loop through fallback languages if found then -- replace output table with a table containing the best value out = { bestval } else -- more than one value and none of them on the list of fallback languages -- sod it, just give them the first one out = { out[1] } end end return assembleoutput(out, frame.args, qid, propertyID) else return props -- no property or local parameter supplied end -- of test for success end ------------------------------------------------------------------------------- -- getPropertyIDs takes most of the usual parameters. -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented. -- It returns the Entity-IDs (Qids) of the values of a property if it is a Wikibase-Entity. -- Otherwise it returns nothing. ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p._getPropertyIDs = function(args) args.reqranks = setRanks(args.rank) args.langobj = findLang(args.lang) args.lang = args.langobj.code -- change default for noicon to true args.noicon = tostring(parseParam(args.noicon or "", true)) local f = {} f.args = args local pid = mw.text.trim(args[1] or ""):upper() -- get the qid and table of claims for the property, or nothing and the local value passed local qid, props = parseInput(f, args[2], pid) if not qid then return props end if not props[1] then return nil end local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 local out = {} for i, v in ipairs(props) do local snak = v.mainsnak if ( snak.datatype == "wikibase-item" ) and ( v.rank and args.reqranks[v.rank:sub(1, 1)] ) and ( snak.snaktype == "value" ) and ( sourced(v) or not onlysrc ) then out[#out+1] = snak.datavalue.value.id end if maxvals > 0 and #out >= maxvals then break end end return assembleoutput(out, args, qid, pid) end p.getPropertyIDs = function(frame) local args = frame.args return p._getPropertyIDs(args) end ------------------------------------------------------------------------------- -- getQualifierIDs takes most of the usual parameters. -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented. -- It takes a property-id as the first unnamed parameter, and an optional parameter qlist -- which is a list of qualifier property-ids to search for (default is "ALL") -- It returns the Entity-IDs (Qids) of the values of a property if it is a Wikibase-Entity. -- Otherwise it returns nothing. ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p.getQualifierIDs = function(frame) local args = frame.args args.reqranks = setRanks(args.rank) args.langobj = findLang(args.lang) args.lang = args.langobj.code -- change default for noicon to true args.noicon = tostring(parseParam(args.noicon or "", true)) local f = {} f.args = args local pid = mw.text.trim(args[1] or ""):upper() -- get the qid and table of claims for the property, or nothing and the local value passed local qid, props = parseInput(f, args[2], pid) if not qid then return props end if not props[1] then return nil end -- get the other parameters local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 local qlist = args.qlist or "" if qlist == "" then qlist = "ALL" end qlist = qlist:gsub("[%p%s]+", " ") .. " " local out = {} for i, v in ipairs(props) do local snak = v.mainsnak if ( v.rank and args.reqranks[v.rank:sub(1, 1)] ) and ( snak.snaktype == "value" ) and ( sourced(v) or not onlysrc ) then if v.qualifiers then for k1, v1 in pairs(v.qualifiers) do if qlist == "ALL " or qlist:match(k1 .. " ") then for i2, v2 in ipairs(v1) do if v2.datatype == "wikibase-item" and v2.snaktype == "value" then out[#out+1] = v2.datavalue.value.id end -- of test that id exists end -- of loop through qualifier values end -- of test for kq in qlist end -- of loop through qualifiers end -- of test for qualifiers end -- of test for rank value, sourced, and value exists if maxvals > 0 and #out >= maxvals then break end end -- of loop through property values return assembleoutput(out, args, qid, pid) end ------------------------------------------------------------------------------- -- getPropOfProp takes two propertyIDs: prop1 and prop2 (as well as the usual parameters) -- If the value(s) of prop1 are of type "wikibase-item" then it returns the value(s) of prop2 -- of each of those wikibase-items. -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p._getPropOfProp = function(args) -- parameter sets for commonly used groups of parameters local paraset = tonumber(args.ps or args.parameterset or 0) if paraset == 1 then -- a common setting args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" elseif paraset == 2 then -- equivalent to raw args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" args.linked = "no" args.pd = "true" elseif paraset == 3 then -- third set goes here end args.reqranks = setRanks(args.rank) args.langobj = findLang(args.lang) args.lang = args.langobj.code local pid1 = args.prop1 or args.pid1 or "" local pid2 = args.prop2 or args.pid2 or "" if pid1 == "" or pid2 == "" then return nil end local f = {} f.args = args local qid1, statements1 = parseInput(f, args[1], pid1) -- parseInput nulls empty args[1] and returns args[1] if nothing on Wikidata if not qid1 then return statements1 end -- otherwise it returns the qid and a table for the statement local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 local qualID = mw.text.trim(args.qual or ""):upper() if qualID == "" then qualID = nil end local out = {} for k, v in ipairs(statements1) do if not onlysrc or sourced(v) then local snak = v.mainsnak if snak.datatype == "wikibase-item" and snak.snaktype == "value" then local qid2 = snak.datavalue.value.id local statements2 = {} if args.reqranks.b then statements2 = mw.wikibase.getBestStatements(qid2, pid2) else statements2 = mw.wikibase.getAllStatements(qid2, pid2) end if statements2[1] then local out2 = propertyvalueandquals(statements2, args, qualID) out[#out+1] = assembleoutput(out2, args, qid2, pid2) end end -- of test for valid property1 value end -- of test for sourced if maxvals > 0 and #out >= maxvals then break end end -- of loop through values of property1 return assembleoutput(out, args, qid1, pid1) end p.getPropOfProp = function(frame) local args= frame.args if not args.prop1 and not args.pid1 then args = frame:getParent().args if not args.prop1 and not args.pid1 then return i18n.errors["No property supplied"] end end return p._getPropOfProp(args) end ------------------------------------------------------------------------------- -- getAwardCat takes most of the usual parameters. If the item has values of P166 (award received), -- then it examines each of those awards for P2517 (category for recipients of this award). -- If it exists, it returns the corresponding category, -- with the item's P734 (family name) as sort key, or no sort key if there is no family name. -- The sort key may be overridden by the parameter |sortkey (alias |sk). -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p.getAwardCat = function(frame) frame.args.reqranks = setRanks(frame.args.rank) frame.args.langobj = findLang(frame.args.lang) frame.args.lang = frame.args.langobj.code local args = frame.args args.sep = " " local pid1 = args.prop1 or "P166" local pid2 = args.prop2 or "P2517" if pid1 == "" or pid2 == "" then return nil end -- locally supplied value: local localval = mw.text.trim(args[1] or "") local qid1, statements1 = parseInput(frame, localval, pid1) if not qid1 then return localval end -- linkprefix (strip quotes) local lp = (args.linkprefix or args.lp or ""):gsub('"', '') -- sort key (strip quotes, hyphens and periods): local sk = (args.sortkey or args.sk or ""):gsub('["-.]', '') -- family name: local famname = "" if sk == "" then local p734 = mw.wikibase.getBestStatements(qid1, "P734")[1] local p734id = p734 and p734.mainsnak.snaktype == "value" and p734.mainsnak.datavalue.value.id or "" famname = mw.wikibase.getSitelink(p734id) or "" -- strip namespace and disambigation local pos = famname:find(":") or 0 famname = famname:sub(pos+1):gsub("%s%(.+%)$", "") if famname == "" then local lbl = mw.wikibase.getLabel(p734id) famname = lbl and mw.text.nowiki(lbl) or "" end end local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 local qualID = mw.text.trim(args.qual or ""):upper() if qualID == "" then qualID = nil end local out = {} for k, v in ipairs(statements1) do if not onlysrc or sourced(v) then local snak = v.mainsnak if snak.datatype == "wikibase-item" and snak.snaktype == "value" then local qid2 = snak.datavalue.value.id local statements2 = {} if args.reqranks.b then statements2 = mw.wikibase.getBestStatements(qid2, pid2) else statements2 = mw.wikibase.getAllStatements(qid2, pid2) end if statements2[1] and statements2[1].mainsnak.snaktype == "value" then local qid3 = statements2[1].mainsnak.datavalue.value.id local sitelink = mw.wikibase.getSitelink(qid3) -- if there's no local sitelink, create the sitelink from English label if not sitelink then local lbl = mw.wikibase.getLabelByLang(qid3, "en") if lbl then if lbl:sub(1,9) == "Category:" then sitelink = mw.text.nowiki(lbl) else sitelink = "Category:" .. mw.text.nowiki(lbl) end end end if sitelink then if sk ~= "" then out[#out+1] = "[[" .. lp .. sitelink .. "|" .. sk .. "]]" elseif famname ~= "" then out[#out+1] = "[[" .. lp .. sitelink .. "|" .. famname .. "]]" else out[#out+1] = "[[" .. lp .. sitelink .. "]]" end -- of check for sort keys end -- of test for sitelink end -- of test for category end -- of test for wikibase item has a value end -- of test for sourced if maxvals > 0 and #out >= maxvals then break end end -- of loop through values of property1 return assembleoutput(out, args, qid1, pid1) end ------------------------------------------------------------------------------- -- getIntersectCat takes most of the usual parameters. -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented -- It takes two properties, |prop1 and |prop2 (e.g. occupation and country of citizenship) -- Each property's value is a wiki-base entity -- For each value of the first parameter (ranks implemented) it fetches the value's main category -- and then each value of the second parameter (possibly substituting a simpler description) -- then it returns all of the categories representing the intersection of those properties, -- (e.g. Category:Actors from Canada). A joining term may be supplied (e.g. |join=from). -- The item's P734 (family name) is the sort key, or no sort key if there is no family name. -- The sort key may be overridden by the parameter |sortkey (alias |sk). ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput; ------------------------------------------------------------------------------- p.getIntersectCat = function(frame) frame.args.reqranks = setRanks(frame.args.rank) frame.args.langobj = findLang(frame.args.lang) frame.args.lang = frame.args.langobj.code local args = frame.args args.sep = " " args.linked = "no" local pid1 = args.prop1 or "P106" local pid2 = args.prop2 or "P27" if pid1 == "" or pid2 == "" then return nil end local qid, statements1 = parseInput(frame, "", pid1) if not qid then return nil end local qid, statements2 = parseInput(frame, "", pid2) if not qid then return nil end -- topics like countries may have different names in categories from their label in Wikidata local subs_exists, subs = pcall(mw.loadData, "Module:WikidataIB/subs") local join = args.join or "" local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 -- linkprefix (strip quotes) local lp = (args.linkprefix or args.lp or ""):gsub('"', '') -- sort key (strip quotes, hyphens and periods): local sk = (args.sortkey or args.sk or ""):gsub('["-.]', '') -- family name: local famname = "" if sk == "" then local p734 = mw.wikibase.getBestStatements(qid, "P734")[1] local p734id = p734 and p734.mainsnak.snaktype == "value" and p734.mainsnak.datavalue.value.id or "" famname = mw.wikibase.getSitelink(p734id) or "" -- strip namespace and disambigation local pos = famname:find(":") or 0 famname = famname:sub(pos+1):gsub("%s%(.+%)$", "") if famname == "" then local lbl = mw.wikibase.getLabel(p734id) famname = lbl and mw.text.nowiki(lbl) or "" end end local cat1 = {} for k, v in ipairs(statements1) do if not onlysrc or sourced(v) then -- get the ID representing the value of the property local pvalID = (v.mainsnak.snaktype == "value") and v.mainsnak.datavalue.value.id if pvalID then -- get the topic's main category (P910) for that entity local p910 = mw.wikibase.getBestStatements(pvalID, "P910")[1] if p910 and p910.mainsnak.snaktype == "value" then local tmcID = p910.mainsnak.datavalue.value.id -- use sitelink or the English label for the cat local cat = mw.wikibase.getSitelink(tmcID) if not cat then local lbl = mw.wikibase.getLabelByLang(tmcID, "en") if lbl then if lbl:sub(1,9) == "Category:" then cat = mw.text.nowiki(lbl) else cat = "Category:" .. mw.text.nowiki(lbl) end end end cat1[#cat1+1] = cat end -- of test for topic's main category exists end -- of test for property has vaild value end -- of test for sourced if maxvals > 0 and #cat1 >= maxvals then break end end local cat2 = {} for k, v in ipairs(statements2) do if not onlysrc or sourced(v) then local cat = rendersnak(v, args) if subs[cat] then cat = subs[cat] end cat2[#cat2+1] = cat end if maxvals > 0 and #cat2 >= maxvals then break end end local out = {} for k1, v1 in ipairs(cat1) do for k2, v2 in ipairs(cat2) do if sk ~= "" then out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. sk .. "]]" elseif famname ~= "" then out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "|" .. famname .. "]]" else out[#out+1] = "[[" .. lp .. v1 .. " " .. join .. " " .. v2 .. "]]" end -- of check for sort keys end end args.noicon = "true" return assembleoutput(out, args, qid, pid1) end ------------------------------------------------------------------------------- -- qualsToTable takes most of the usual parameters. -- The usual whitelisting, blacklisting, onlysourced, etc. are implemented. -- A qid may be given, and the first unnamed parameter is the property ID, which is of type wikibase item. -- It takes a list of qualifier property IDs as |quals= -- For a given qid and property, it creates the rows of an html table, -- each row being a value of the property (optionally only if the property matches the value in |pval= ) -- each cell being the first value of the qualifier corresponding to the list in |quals ------------------------------------------------------------------------------- -- Dependencies: parseParam; setRanks; parseInput; sourced; ------------------------------------------------------------------------------- p.qualsToTable = function(frame) local args = frame.args local quals = args.quals or "" if quals == "" then return "" end args.reqranks = setRanks(args.rank) local propertyID = mw.text.trim(args[1] or "") local f = {} f.args = args local entityid, props = parseInput(f, "", propertyID) if not entityid then return "" end args.langobj = findLang(args.lang) args.lang = args.langobj.code local pval = args.pval or "" local qplist = mw.text.split(quals, "%p") -- split at punctuation and make a sequential table for i, v in ipairs(qplist) do qplist[i] = mw.text.trim(v):upper() -- remove whitespace and capitalise end local col1 = args.firstcol or "" if col1 ~= "" then col1 = col1 .. "</td><td>" end local emptycell = args.emptycell or "&nbsp;" -- construct a 2-D array of qualifier values in qvals local qvals = {} for i, v in ipairs(props) do local skip = false if pval ~= "" then local pid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id if pid ~= pval then skip = true end end if not skip then local qval = {} local vqualifiers = v.qualifiers or {} -- go through list of wanted qualifier properties for i1, v1 in ipairs(qplist) do -- check for that property ID in the statement's qualifiers local qv, qtype if vqualifiers[v1] then qtype = vqualifiers[v1][1].datatype if qtype == "time" then if vqualifiers[v1][1].snaktype == "value" then qv = mw.wikibase.renderSnak(vqualifiers[v1][1]) qv = frame:expandTemplate{title="dts", args={qv}} else qv = "?" end elseif qtype == "url" then if vqualifiers[v1][1].snaktype == "value" then qv = mw.wikibase.renderSnak(vqualifiers[v1][1]) local display = mw.ustring.match( mw.uri.decode(qv, "WIKI"), "([%w ]+)$" ) if display then qv = "[" .. qv .. " " .. display .. "]" end end else qv = mw.wikibase.formatValue(vqualifiers[v1][1]) end end -- record either the value or a placeholder qval[i1] = qv or emptycell end -- of loop through list of qualifiers -- add the list of qualifier values as a "row" in the main list qvals[#qvals+1] = qval end end -- of for each value loop local out = {} for i, v in ipairs(qvals) do out[i] = "<tr><td>" .. col1 .. table.concat(qvals[i], "</td><td>") .. "</td></tr>" end return table.concat(out, "\n") end ------------------------------------------------------------------------------- -- getGlobe takes an optional qid of a Wikidata entity passed as |qid= -- otherwise it uses the linked item for the current page. -- If returns the Qid of the globe used in P625 (coordinate location), -- or nil if there isn't one. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getGlobe = function(frame) local qid = frame.args.qid or frame.args[1] or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end local coords = mw.wikibase.getBestStatements(qid, "P625")[1] local globeid if coords and coords.mainsnak.snaktype == "value" then globeid = coords.mainsnak.datavalue.value.globe:match("(Q%d+)") end return globeid end ------------------------------------------------------------------------------- -- getCommonsLink takes an optional qid of a Wikidata entity passed as |qid= -- It returns one of the following in order of preference: -- the Commons sitelink of the linked Wikidata item; -- the Commons sitelink of the topic's main category of the linked Wikidata item; ------------------------------------------------------------------------------- -- Dependencies: _getCommonslink(); _getSitelink(); parseParam() ------------------------------------------------------------------------------- p.getCommonsLink = function(frame) local oc = frame.args.onlycat or frame.args.onlycategories local fb = parseParam(frame.args.fallback or frame.args.fb, true) return _getCommonslink(frame.args.qid, oc, fb) end ------------------------------------------------------------------------------- -- getSitelink takes the qid of a Wikidata entity passed as |qid= -- It takes an optional parameter |wiki= to determine which wiki is to be checked for a sitelink -- If the parameter is blank, then it uses the local wiki. -- If there is a sitelink to an article available, it returns the plain text link to the article -- If there is no sitelink, it returns nil. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getSiteLink = function(frame) return _getSitelink(frame.args.qid, frame.args.wiki or mw.text.trim(frame.args[1] or "")) end ------------------------------------------------------------------------------- -- getLink has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= -- If there is a sitelink to an article on the local Wiki, it returns a link to the article -- with the Wikidata label as the displayed text. -- If there is no sitelink, it returns the label as plain text. -- If there is no label in the local language, it displays the qid instead. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getLink = function(frame) local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") if itemID == "" then return end local sitelink = mw.wikibase.getSitelink(itemID) local label = labelOrId(itemID) if sitelink then return "[[:" .. sitelink .. "|" .. label .. "]]" else return label end end ------------------------------------------------------------------------------- -- getLabel has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= -- It returns the Wikidata label for the local language as plain text. -- If there is no label in the local language, it displays the qid instead. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getLabel = function(frame) local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") if itemID == "" then return end local lang = frame.args.lang or "" if lang == "" then lang = nil end local label = labelOrId(itemID, lang) return label end ------------------------------------------------------------------------------- -- label has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= -- if no qid is supplied, it uses the qid associated with the current page. -- It returns the Wikidata label for the local language as plain text. -- If there is no label in the local language, it returns nil. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.label = function(frame) local qid = mw.text.trim(frame.args[1] or frame.args.qid or "") if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return end local lang = frame.args.lang or "" if lang == "" then lang = nil end local label, success = labelOrId(qid, lang) if success then return label end end ------------------------------------------------------------------------------- -- getAT (Article Title) -- has the qid of a Wikidata entity passed as the first unnamed parameter or as |qid= -- If there is a sitelink to an article on the local Wiki, it returns the sitelink as plain text. -- If there is no sitelink or qid supplied, it returns nothing. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getAT = function(frame) local itemID = mw.text.trim(frame.args[1] or frame.args.qid or "") if itemID == "" then return end return mw.wikibase.getSitelink(itemID) end ------------------------------------------------------------------------------- -- getDescription has the qid of a Wikidata entity passed as |qid= -- (it defaults to the associated qid of the current article if omitted) -- and a local parameter passed as the first unnamed parameter. -- Any local parameter passed (other than "Wikidata" or "none") becomes the return value. -- It returns the article description for the Wikidata entity if the local parameter is "Wikidata". -- Nothing is returned if the description doesn't exist or "none" is passed as the local parameter. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getDescription = function(frame) local desc = mw.text.trim(frame.args[1] or "") local itemID = mw.text.trim(frame.args.qid or "") if itemID == "" then itemID = nil end if desc:lower() == 'wikidata' then return mw.wikibase.getDescription(itemID) elseif desc:lower() == 'none' then return nil else return desc end end ------------------------------------------------------------------------------- -- getAliases has the qid of a Wikidata entity passed as |qid= -- (it defaults to the associated qid of the current article if omitted) -- and a local parameter passed as the first unnamed parameter. -- It implements blacklisting and whitelisting with a field name of "alias" by default. -- Any local parameter passed becomes the return value. -- Otherwise it returns the aliases for the Wikidata entity with the usual list options. -- Nothing is returned if the aliases do not exist. ------------------------------------------------------------------------------- -- Dependencies: findLang(); assembleoutput() ------------------------------------------------------------------------------- p.getAliases = function(frame) local args = frame.args local fieldname = args.name or "" if fieldname == "" then fieldname = "alias" end local blacklist = args.suppressfields or args.spf or "" if blacklist:find(fieldname) then return nil end local localval = mw.text.trim(args[1] or "") if localval ~= "" then return localval end local whitelist = args.fetchwikidata or args.fwd or "" if whitelist == "" then whitelist = "NONE" end if not (whitelist == 'ALL' or whitelist:find(fieldname)) then return nil end local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid or not mw.wikibase.entityExists(qid) then return nil end local aliases = mw.wikibase.getEntity(qid).aliases if not aliases then return nil end args.langobj = findLang(args.lang) local langcode = args.langobj.code args.lang = langcode local out = {} for k1, v1 in pairs(aliases) do if v1[1].language == langcode then for k1, v2 in ipairs(v1) do out[#out+1] = v2.value end break end end return assembleoutput(out, args, qid) end ------------------------------------------------------------------------------- -- pageId returns the page id (entity ID, Qnnn) of the current page -- returns nothing if the page is not connected to Wikidata ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.pageId = function(frame) return mw.wikibase.getEntityIdForCurrentPage() end ------------------------------------------------------------------------------- -- formatDate is a wrapper to export the private function format_Date ------------------------------------------------------------------------------- -- Dependencies: format_Date(); ------------------------------------------------------------------------------- p.formatDate = function(frame) return format_Date(frame.args[1], frame.args.df, frame.args.bc) end ------------------------------------------------------------------------------- -- location is a wrapper to export the private function _location -- it takes the entity-id as qid or the first unnamed parameter -- optional boolean parameter first toggles the display of the first item -- optional boolean parameter skip toggles the display to skip to the last item -- parameter debug=<y/n> (default 'n') adds error msg if not a location ------------------------------------------------------------------------------- -- Dependencies: _location(); ------------------------------------------------------------------------------- p.location = function(frame) local debug = (frame.args.debug or ""):sub(1, 1):lower() if debug == "" then debug = "n" end local qid = mw.text.trim(frame.args.qid or frame.args[1] or ""):upper() if qid == "" then qid=mw.wikibase.getEntityIdForCurrentPage() end if not qid then if debug ~= "n" then return i18n.errors["entity-not-found"] else return nil end end local first = mw.text.trim(frame.args.first or "") local skip = mw.text.trim(frame.args.skip or "") return table.concat( _location(qid, first, skip), ", " ) end ------------------------------------------------------------------------------- -- checkBlacklist implements a test to check whether a named field is allowed -- returns true if the field is not blacklisted (i.e. allowed) -- returns false if the field is blacklisted (i.e. disallowed) -- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Joe |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}} -- displays "blacklisted" -- {{#if:{{#invoke:WikidataIB |checkBlacklist |name=Jim |suppressfields=Dave; Joe; Fred}} | not blacklisted | blacklisted}} -- displays "not blacklisted" ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.checkBlacklist = function(frame) local blacklist = frame.args.suppressfields or frame.args.spf or "" local fieldname = frame.args.name or "" if blacklist ~= "" and fieldname ~= "" then if blacklist:find(fieldname) then return false else return true end else -- one of the fields is missing: let's call that "not on the list" return true end end ------------------------------------------------------------------------------- -- emptyor returns nil if its first unnamed argument is just punctuation, whitespace or html tags -- otherwise it returns the argument unchanged (including leading/trailing space). -- If the argument may contain "=", then it must be called explicitly: -- |1=arg -- (In that case, leading and trailing spaces are trimmed) -- It finds use in infoboxes where it can replace tests like: -- {{#if: {{#invoke:WikidatIB |getvalue |P99 |fwd=ALL}} | <span class="xxx">{{#invoke:WikidatIB |getvalue |P99 |fwd=ALL}}</span> | }} -- with a form that uses just a single call to Wikidata: -- {{#invoke |WikidataIB |emptyor |1= <span class="xxx">{{#invoke:WikidataIB |getvalue |P99 |fwd=ALL}}</span> }} ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.emptyor = function(frame) local s = frame.args[1] or "" if s == "" then return nil end local sx = s:gsub("%s", ""):gsub("<[^>]*>", ""):gsub("%p", "") if sx == "" then return nil else return s end end ------------------------------------------------------------------------------- -- labelorid is a public function to expose the output of labelOrId() -- Pass the Q-number as |qid= or as an unnamed parameter. -- It returns the Wikidata label for that entity or the qid if no label exists. ------------------------------------------------------------------------------- -- Dependencies: labelOrId ------------------------------------------------------------------------------- p.labelorid = function(frame) return (labelOrId(frame.args.qid or frame.args[1])) end ------------------------------------------------------------------------------- -- getLang returns the MediaWiki language code of the current content. -- If optional parameter |style=full, it returns the language name. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getLang = function(frame) local style = (frame.args.style or ""):lower() local langcode = mw.language.getContentLanguage().code if style == "full" then return mw.language.fetchLanguageName( langcode ) end return langcode end ------------------------------------------------------------------------------- -- getItemLangCode takes a qid parameter (using the current page's qid if blank) -- If the item for that qid has property country (P17) it looks at the first preferred value -- If the country has an official language (P37), it looks at the first preferred value -- If that official language has a language code (P424), it returns the first preferred value -- Otherwise it returns nothing. ------------------------------------------------------------------------------- -- Dependencies: _getItemLangCode() ------------------------------------------------------------------------------- p.getItemLangCode = function(frame) return _getItemLangCode(frame.args.qid or frame.args[1]) end ------------------------------------------------------------------------------- -- findLanguage exports the local findLang() function -- It takes an optional language code and returns, in order of preference: -- the code if a known language; -- the user's language, if set; -- the server's content language. ------------------------------------------------------------------------------- -- Dependencies: findLang ------------------------------------------------------------------------------- p.findLanguage = function(frame) return findLang(frame.args.lang or frame.args[1]).code end ------------------------------------------------------------------------------- -- getQid returns the qid, if supplied -- failing that, the Wikidata entity ID of the "category's main topic (P301)", if it exists -- failing that, the Wikidata entity ID associated with the current page, if it exists -- otherwise, nothing ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getQid = function(frame) local qid = (frame.args.qid or ""):upper() -- check if a qid was passed; if so, return it: if qid ~= "" then return qid end -- check if there's a "category's main topic (P301)": qid = mw.wikibase.getEntityIdForCurrentPage() if qid then local prop301 = mw.wikibase.getBestStatements(qid, "P301") if prop301[1] then local mctid = prop301[1].mainsnak.datavalue.value.id if mctid then return mctid end end end -- otherwise return the page qid (if any) return qid end ------------------------------------------------------------------------------- -- followQid takes four optional parameters: qid, props, list and all. -- If qid is not given, it uses the qid for the connected page -- or returns nil if there isn't one. -- props is a list of properties, separated by punctuation. -- If props is given, the Wikidata item for the qid is examined for each property in turn. -- If that property contains a value that is another Wikibase-item, that item's qid is returned, -- and the search terminates, unless |all=y when all of the qids are returned, separated by spaces. -- If |list= is set to a template, the qids are passed as arguments to the template. -- If props is not given, the qid is returned. ------------------------------------------------------------------------------- -- Dependencies: parseParam() ------------------------------------------------------------------------------- p._followQid = function(args) local qid = (args.qid or ""):upper() local all = parseParam(args.all, false) local list = args.list or "" if list == "" then list = nil end if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return nil end local out = {} local props = (args.props or ""):upper() if props ~= "" then for p in mw.text.gsplit(props, "%p") do -- split at punctuation and iterate p = mw.text.trim(p) for i, v in ipairs( mw.wikibase.getBestStatements(qid, p) ) do local linkedid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id if linkedid then if all then out[#out+1] = linkedid else return linkedid end -- test for all or just the first one found end -- test for value exists for that property end -- loop through values of property to follow end -- loop through list of properties to follow end if #out > 0 then local ret = "" if list then ret = mw.getCurrentFrame():expandTemplate{title = list, args = out} else ret = table.concat(out, " ") end return ret else return qid end end p.followQid = function(frame) return p._followQid(frame.args) end ------------------------------------------------------------------------------- -- globalSiteID returns the globalSiteID for the current wiki -- e.g. returns "enwiki" for the English Wikipedia, "enwikisource" for English Wikisource, etc. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.globalSiteID = function(frame) return mw.wikibase.getGlobalSiteId() end ------------------------------------------------------------------------------- -- siteID returns the root of the globalSiteID -- e.g. "en" for "enwiki", "enwikisource", etc. -- treats "en-gb" as "en", etc. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.siteID = function(frame) local txtlang = frame:callParserFunction('int', {'lang'}) or "" -- This deals with specific exceptions: be-tarask -> be-x-old if txtlang == "be-tarask" then return "be_x_old" end local pos = txtlang:find("-") local ret = "" if pos then ret = txtlang:sub(1, pos-1) else ret = txtlang end return ret end ------------------------------------------------------------------------------- -- projID returns the code used to link to the reader's language's project -- e.g "en" for [[:en:WikidataIB]] -- treats "en-gb" as "en", etc. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.projID = function(frame) local txtlang = frame:callParserFunction('int', {'lang'}) or "" -- This deals with specific exceptions: be-tarask -> be-x-old if txtlang == "be-tarask" then return "be-x-old" end local pos = txtlang:find("-") local ret = "" if pos then ret = txtlang:sub(1, pos-1) else ret = txtlang end return ret end ------------------------------------------------------------------------------- -- formatNumber formats a number according to the the supplied language code ("|lang=") -- or the default language if not supplied. -- The number is the first unnamed parameter or "|num=" ------------------------------------------------------------------------------- -- Dependencies: findLang() ------------------------------------------------------------------------------- p.formatNumber = function(frame) local lang local num = tonumber(frame.args[1] or frame.args.num) or 0 lang = findLang(frame.args.lang) return lang:formatNum( num ) end ------------------------------------------------------------------------------- -- examine dumps the property (the unnamed parameter or pid) -- from the item given by the parameter 'qid' (or the other unnamed parameter) -- or from the item corresponding to the current page if qid is not supplied. -- e.g. {{#invoke:WikidataIB |examine |pid=P26 |qid=Q42}} -- or {{#invoke:WikidataIB |examine |P26 |Q42}} or any combination of these -- or {{#invoke:WikidataIB |examine |P26}} for the current page. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.examine = function( frame ) local args if frame.args[1] or frame.args.pid or frame.args.qid then args = frame.args else args = frame:getParent().args end local par = {} local pid = (args.pid or ""):upper() local qid = (args.qid or ""):upper() par[1] = mw.text.trim( args[1] or "" ):upper() par[2] = mw.text.trim( args[2] or "" ):upper() table.sort(par) if par[2]:sub(1,1) == "P" then par[1], par[2] = par[2], par[1] end if pid == "" then pid = par[1] end if qid == "" then qid = par[2] end local q1 = qid:sub(1,1) if pid:sub(1,1) ~= "P" then return "No property supplied" end if q1 ~= "Q" and q1 ~= "M" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return "No item for this page" end return "<pre>" .. mw.dumpObject( mw.wikibase.getAllStatements( qid, pid ) ) .. "</pre>" end ------------------------------------------------------------------------------- -- checkvalue looks for 'val' as a wikibase-item value of a property (the unnamed parameter or pid) -- from the item given by the parameter 'qid' -- or from the Wikidata item associated with the current page if qid is not supplied. -- It only checks ranks that are requested (preferred and normal by default) -- If property is not supplied, then P31 (instance of) is assumed. -- It returns val if found or nothing if not found. -- e.g. {{#invoke:WikidataIB |checkvalue |val=Q5 |pid=P31 |qid=Q42}} -- or {{#invoke:WikidataIB |checkvalue |val=Q5 |P31 |qid=Q42}} -- or {{#invoke:WikidataIB |checkvalue |val=Q5 |qid=Q42}} -- or {{#invoke:WikidataIB |checkvalue |val=Q5 |P31}} for the current page. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.checkvalue = function( frame ) local args if frame.args.val then args = frame.args else args = frame:getParent().args end local val = args.val if not val then return nil end local pid = mw.text.trim(args.pid or args[1] or "P31"):upper() local qid = (args.qid or ""):upper() if pid:sub(1,1) ~= "P" then return nil end if qid:sub(1,1) ~= "Q" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return nil end local ranks = setRanks(args.rank) local stats = {} if ranks.b then stats = mw.wikibase.getBestStatements(qid, pid) else stats = mw.wikibase.getAllStatements( qid, pid ) end if not stats[1] then return nil end if stats[1].mainsnak.datatype == "wikibase-item" then for k, v in pairs( stats ) do local ms = v.mainsnak if ranks[v.rank:sub(1,1)] and ms.snaktype == "value" and ms.datavalue.value.id == val then return val end end end return nil end ------------------------------------------------------------------------------- -- url2 takes a parameter url= that is a proper url and formats it for use in an infobox. -- If no parameter is supplied, it returns nothing. -- This is the equivalent of Template:URL -- but it keeps the "edit at Wikidata" pen icon out of the microformat. -- Usually it will take its url parameter directly from a Wikidata call: -- e.g. {{#invoke:WikidataIB |url2 |url={{wdib |P856 |qid=Q23317 |fwd=ALL |osd=no}} }} ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.url2 = function(frame) local txt = frame.args.url or "" if txt == "" then return nil end -- extract any icon local url, icon = txt:match("(.+)&nbsp;(.+)") -- make sure there's at least a space at the end url = (url or txt) .. " " icon = icon or "" -- extract any protocol like https:// local prot = url:match("(https*://).+[ \"\']") -- extract address local addr = "" if prot then addr = url:match("https*://(.+)[ \"\']") or " " else prot = "//" addr = url:match("[^%p%s]+%.(.+)[ \"\']") or " " end -- strip trailing / from end of domain-only url and add <wbr/> before . and / local disp, n = addr:gsub( "^([^/]+)/$", "%1" ):gsub("%/", "<wbr/>/"):gsub("%.", "<wbr/>.") return '<span class="url">[' .. prot .. addr .. " " .. disp .. "]</span>&nbsp;" .. icon end ------------------------------------------------------------------------------- -- getWebsite fetches the Official website (P856) and formats it for use in an infobox. -- This is similar to Template:Official website but with a url displayed, -- and it adds the "edit at Wikidata" pen icon beyond the microformat if enabled. -- A local value will override the Wikidata value. "NONE" returns nothing. -- e.g. {{#invoke:WikidataIB |getWebsite |qid= |noicon= |lang= |url= }} ------------------------------------------------------------------------------- -- Dependencies: findLang(); parseParam(); ------------------------------------------------------------------------------- p.getWebsite = function(frame) local url = frame.args.url or "" if url:upper() == "NONE" then return nil end local urls = {} local quals = {} local qid = frame.args.qid or "" if url and url ~= "" then urls[1] = url else if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return nil end local prop856 = mw.wikibase.getBestStatements(qid, "P856") for k, v in pairs(prop856) do if v.mainsnak.snaktype == "value" then urls[#urls+1] = v.mainsnak.datavalue.value if v.qualifiers and v.qualifiers["P1065"] then -- just take the first archive url (P1065) local au = v.qualifiers["P1065"][1] if au.snaktype == "value" then quals[#urls] = au.datavalue.value end -- test for archive url having a value end -- test for qualifers end -- test for website having a value end -- loop through website(s) end if #urls == 0 then return nil end local out = {} for i, u in ipairs(urls) do local link = quals[i] or u local prot, addr = u:match("(http[s]*://)(.+)") addr = addr or u local disp, n = addr:gsub("%.", "<wbr/>%.") out[#out+1] = '<span class="url">[' .. link .. " " .. disp .. "]</span>" end local langcode = findLang(frame.args.lang).code local noicon = parseParam(frame.args.noicon, false) if url == "" and not noicon then out[#out] = out[#out] .. createicon(langcode, qid, "P856") end local ret = "" if #out > 1 then ret = mw.getCurrentFrame():expandTemplate{title = "ubl", args = out} else ret = out[1] end return ret end ------------------------------------------------------------------------------- -- getAllLabels fetches the set of labels and formats it for display as wikitext. -- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getAllLabels = function(frame) local args = frame.args or frame:getParent().args or {} local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end local labels = mw.wikibase.getEntity(qid).labels if not labels then return i18n["labels-not-found"] end local out = {} for k, v in pairs(labels) do out[#out+1] = v.value .. " (" .. v.language .. ")" end return table.concat(out, "; ") end ------------------------------------------------------------------------------- -- getAllDescriptions fetches the set of descriptions and formats it for display as wikitext. -- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getAllDescriptions = function(frame) local args = frame.args or frame:getParent().args or {} local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end local descriptions = mw.wikibase.getEntity(qid).descriptions if not descriptions then return i18n["descriptions-not-found"] end local out = {} for k, v in pairs(descriptions) do out[#out+1] = v.value .. " (" .. v.language .. ")" end return table.concat(out, "; ") end ------------------------------------------------------------------------------- -- getAllAliases fetches the set of aliases and formats it for display as wikitext. -- It takes a parameter 'qid' for arbitrary access, otherwise it uses the current page. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.getAllAliases = function(frame) local args = frame.args or frame:getParent().args or {} local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid or not mw.wikibase.entityExists(qid) then return i18n["entity-not-found"] end local aliases = mw.wikibase.getEntity(qid).aliases if not aliases then return i18n["aliases-not-found"] end local out = {} for k1, v1 in pairs(aliases) do local lang = v1[1].language local val = {} for k1, v2 in ipairs(v1) do val[#val+1] = v2.value end out[#out+1] = table.concat(val, ", ") .. " (" .. lang .. ")" end return table.concat(out, "; ") end ------------------------------------------------------------------------------- -- showNoLinks displays the article titles that should not be linked. ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- p.showNoLinks = function(frame) local out = {} for k, v in pairs(donotlink) do out[#out+1] = k end table.sort( out ) return table.concat(out, "; ") end ------------------------------------------------------------------------------- -- checkValidity checks whether the first unnamed parameter represents a valid entity-id, -- that is, something like Q1235 or P123. -- It returns the strings "true" or "false". -- Change false to nil to return "true" or "" (easier to test with #if:). ------------------------------------------------------------------------------- -- Dependencies: none ------------------------------------------------------------------------------- function p.checkValidity(frame) local id = mw.text.trim(frame.args[1] or "") if mw.wikibase.isValidEntityId(id) then return true else return false end end ------------------------------------------------------------------------------- -- getEntityFromTitle returns the Entity-ID (Q-number) for a given title. -- Modification of Module:ResolveEntityId -- The title is the first unnamed parameter. -- The site parameter determines the site/language for the title. Defaults to current wiki. -- The showdab parameter determines whether dab pages should return the Q-number or nil. Defaults to true. -- Returns the Q-number or nil if it does not exist. ------------------------------------------------------------------------------- -- Dependencies: parseParam ------------------------------------------------------------------------------- function p.getEntityFromTitle(frame) local args=frame.args if not args[1] then args=frame:getParent().args end if not args[1] then return nil end local title = mw.text.trim(args[1]) local site = args.site or "" local showdab = parseParam(args.showdab, true) local qid = mw.wikibase.getEntityIdForTitle(title, site) if qid then local prop31 = mw.wikibase.getBestStatements(qid, "P31")[1] if not showdab and prop31 and prop31.mainsnak.datavalue.value.id == "Q4167410" then return nil else return qid end end end ------------------------------------------------------------------------------- -- getDatePrecision returns the number representing the precision of the first best date value -- for the given property. -- It takes the qid and property ID -- The meanings are given at https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times -- 0 = 1 billion years .. 6 = millennium, 7 = century, 8 = decade, 9 = year, 10 = month, 11 = day -- Returns 0 (or the second unnamed parameter) if the Wikidata does not exist. ------------------------------------------------------------------------------- -- Dependencies: parseParam; sourced; ------------------------------------------------------------------------------- function p.getDatePrecision(frame) local args=frame.args if not args[1] then args=frame:getParent().args end local default = tonumber(args[2] or args.default) or 0 local prop = mw.text.trim(args[1] or "") if prop == "" then return default end local qid = args.qid or "" if qid == "" then qid = mw.wikibase.getEntityIdForCurrentPage() end if not qid then return default end local onlysrc = parseParam(args.onlysourced or args.osd, true) local stat = mw.wikibase.getBestStatements(qid, prop) for i, v in ipairs(stat) do local prec = (onlysrc == false or sourced(v)) and v.mainsnak.datavalue and v.mainsnak.datavalue.value and v.mainsnak.datavalue.value.precision if prec then return prec end end return default end return p ------------------------------------------------------------------------------- -- List of exported functions ------------------------------------------------------------------------------- --[[ _getValue getValue getPreferredValue getCoords getQualifierValue getSumOfParts getValueByQual getValueByLang getValueByRefSource getPropertyIDs getQualifierIDs getPropOfProp getAwardCat getIntersectCat getGlobe getCommonsLink getSiteLink getLink getLabel label getAT getDescription getAliases pageId formatDate location checkBlacklist emptyor labelorid getLang getItemLangCode findLanguage getQID followQid globalSiteID siteID projID formatNumber examine checkvalue url2 getWebsite getAllLabels getAllDescriptions getAllAliases showNoLinks checkValidity getEntityFromTitle getDatePrecision --]] ------------------------------------------------------------------------------- q7kv3rt8dg8wlffj47l72o3z133c26q 模块:Cite Q 828 14846 43052 2026-07-07T17:54:02Z 内存溢出的猫 7954 From [[zh:Module:Cite Q]] 43052 Scribunto text/plain -- Version: 2021-10-19 local p = {} require('strict') local wdib = require('Module:WikidataIB/sandbox for Cite Q') local getValue = wdib._getValue local getPropOfProp = wdib._getPropOfProp local followQid = wdib._followQid local getPropertyIDs = wdib._getPropertyIDs local i18n = { ["unknown-author"] = mw.wikibase.getLabel("Q4233718"):gsub("^%l", mw.ustring.upper), ["unknown-author-trackingcat"] = "[[Category:Cite Q - 作者未知]]", ["ordinal"] = { [1] = "st", [2] = "nd", [3] = "rd", ["default"] = "th" }, ["months"] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, } ------------------------------------------------------------------------------- -- makeOrdinal needs to be internationalised along with the above i18n -- takes cardinal number as a numeric and returns the ordinal as a string -- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. ------------------------------------------------------------------------------- p.makeOrdinal = function(cardinal) local card = tonumber(cardinal) if not card then return cardinal end local ordsuffix = i18n.ordinal.default if card % 10 == 1 then ordsuffix = i18n.ordinal[1] elseif card % 10 == 2 then ordsuffix = i18n.ordinal[2] elseif card % 10 == 3 then ordsuffix = i18n.ordinal[3] end -- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' -- similarly for 12 and 13, etc. if (card % 100 == 11) or (card % 100 == 12) or (card % 100 == 13) then ordsuffix = i18n.ordinal.default end return card .. ordsuffix end -- Table of simple properties that can be fetched in roughly the same way: -- id = PXXX -- maxvals = maximum number of multiple values (0 for all) -- linked = "no" suppresses linking -- populate_from_journal = true/false determines whether to look in a journal where the source is published -- rank = "best", "preferred", normal, etc. determines how Wikidata ranks are treated -- others = true - the value for the property goes to "others" section local simple_properties = { publisher = {id = "P123", maxvals = 1}, oclc = {id = "P243", maxvals = 1}, ['publication-place'] = {id = "P291", maxvals = 0, linked = 'no'}, -- publication place (don't put into |place=; is treated specially in {{citation}} if both are given) doi = {id = "P356", maxvals = 1}, -- take care of |doi-broken-date= (WD "reason for deprecation"/"stated as") and |doi-access= (WD "access status")? issue = {id = "P433", maxvals = 0, populate_from_journal = true}, -- distinguish from |number= ("P1545"?) if both are given (still blocked by {{citation}}, but will be supported in the future) pmid = {id = "P698", maxvals = 1}, -- gbooks = {id = "P675", maxvals = 1}, -- to be added to {{citation}} -- ia = {id = "P724", maxvals = 1}, -- to be added to {{citation}} arxiv = {id = "P818", maxvals = 1}, bibcode = {id = "P819", maxvals = 1}, -- take care of |bibcode-access=? jstor = {id = "P888", maxvals = 1}, -- take care of |jstor-access=? mr = {id = "P889", maxvals = 1}, rfc = {id = "P892", maxvals = 1}, zbl = {id = "P894", maxvals = 1}, ssrn = {id = "P893", maxvals = 1}, place = {id = "P1071", maxvals = 0, linked = 'no'}, -- written-at place -- ['total-pages'] = {id = "P1104", maxvals = 0, linked = 'no'}, -- to be added to {{citation}} / COinS &rft.tpages= -- coden = {id = "P1159", maxvals = 1}, -- to be added to {{citation}} / COinS &rft.coden= s2cid = {id = "P8299", maxvals = 1}, -- take care of |s2cid-access=? pmc = {id = "P932", maxvals = 1}, -- take care of |pmc-embargo-date= (WD "reason for deprecation")? lccn = {id = "P1144", maxvals = 1}, hdl = {id = "P1184", maxvals = 1}, -- take care of |hdl-access=? ismn = {id = "P1208", maxvals = 1}, journal = {id = "P1433", maxvals = 1}, citeseerx = {id = "P3784", maxvals = 1}, osti = {id = "P3894", maxvals = 1}, -- take care of |osti-access=? biorxiv = {id = "P3951", maxvals = 1}, asin = {id = "P5749", maxvals = 1}, -- What about |asin-tld=? (WD examples resolve to .com at present, but may change) -- ['catalog-number'] = {id = "P528", maxvals = 0}, -- to be added to {{citation}} / COinS &rft.artnum= isbn = {id = "P212", maxvals = 1, populate_from_journal = true}, -- ISBN 13 issn = {id = "P236", maxvals = 1, populate_from_journal = true}, -- distinguish from |eissn= for electronic issues? -- jfm = {id = "P?", maxvals = 1}, -- Jahrbuch über die Fortschritte der Mathematik (not Zbl) -- sbn = {id = "P?", maxvals = 1}, -- Standard Book Number (predecessor of ISBN, not ICCU) -- message-id = {id = "P?", maxvals = 1}, -- Usenet message ID chapter = {id = "P792", maxvals = 1}, ['publication-date'] = {id = "P577", maxvals = 1, populate_from_journal = true}, -- publication date (don't use |date=; is treated specially in {{citation}} if both are given.) series = {id = "P179", maxvals = 1, populate_from_journal = true}, version = {id = "P348", maxvals = 0}, edition = {id = "P393", maxvals = 0}, volume = {id = "P478", maxvals = 0, populate_from_journal = true}, -- part = {id = "P1545"?, maxvals = 0}, -- to be added to {{citation}} / COinS &rft.part= title = {id = "P1476", rank="p n"}, -- url = {id = "P953", maxvals = 1}, -- deal with this along with archive-url pages = {id = "P304", maxvals = 0, populate_from_journal = true}, at = {id = "P958", maxvals = 0, populate_from_journal = true}, -- also incorporate lines (P7421) and columns (P3903) into this (cite map also supports |section=) -- sheets = {id = "P7416", maxvals = 0, populate_from_journal = true}, -- interviewer = {id = "P?", maxvals = 0}, -- does **not** go to "others" section! Multiple interviewers should be n-enumerated illustrator = {id = "P110", maxvals = 10, others = true}, -- goes to "others" section -- foreword and afterword, when contributions to another author's work, are contributions so belong in |contribution=; -- the writer's name goes in |contributor=; requires |title= and |author= -- However, this might need to add support for multiple contributors and their roles to {{citation}}, see Help_talk:Citation_Style_1#Others -- foreword = {id = "P2679", maxvals = 10, others = true}, -- goes to "others" section -- afterword = {id = "P2680", maxvals = 10, others = true}, -- goes to "others" section composer = {id = "P86", maxvals = 10, others = true}, -- goes to "others" section animator = {id = "P6942", maxvals = 10, others = true}, -- goes to "others" section director = {id = "P57", maxvals = 10, others = true}, -- goes to "others" section screenwriter = {id = "P58", maxvals = 10, others = true}, -- goes to "others" section signatory = {id = "P1891", maxvals = 10, others = true}, -- goes to "others" section presenter = {id = "P371", maxvals = 10, others = true}, -- goes to "others" section performer = {id = "P175", maxvals = 10, others = true}, -- goes to "others" section } --[[--------------------------< 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 _ A R R A Y >-------------------------------------------------------------- Whether needle is in haystack (taken from Module:Citation/CS1/Utilities) ]] 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 --[[--------------------------< A C C E P T _ V A L U E >------------------------------------------------------- Accept WD value by framing in ((...)) if param_val is equal to keyword; else pass-through WD value as is. ]] local function accept_value( param_val, wd_val ) local val = param_val if val then if in_array (val, {'accept', '))((', ':d:'}) then val = '((' .. wd_val .. '))' elseif '((accept))' == val then val = 'accept' elseif '(())(())' == val then val = '))((' elseif '((:d:))' == val then val = ':d:' else val = wd_val end end return val end -- function to fetch a value to display local function makelink(v, out, link, maxpos, wdl) local label if v.mainsnak.snaktype == "value" then if v.mainsnak.datatype == "wikibase-item" then local qnumber = v.mainsnak.datavalue.value.id local sitelink = mw.wikibase.getSitelink(qnumber) if qnumber == "Q2818964" then sitelink = nil end -- suppress link to "Various authors" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = mw.wikibase.getLabel(qnumber) if label then label = mw.text.nowiki(label) else label = qnumber -- should add tracking category end end local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) if sitelink then -- just the plain name, -- but keep a record of the links, using the same index out[position] = label link[position] = sitelink else if wdl then -- show that there's a Wikidata entry available out[position] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]&nbsp;<span title='" .. i18n["errors"]["local-article-not-found"] .. "'>[[File:Wikidata-logo.svg|16px|alt=|link=]]</span>" else -- no Wikidata links wanted, so just give the plain label out[position] = label end end elseif v.mainsnak.datatype == "string" then local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) out[position] = v.mainsnak.datavalue.value else -- not a wikibase-item or a string! end else -- code here if we want to return something when author is "unknown" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = i18n["unknown-author"] .. (i18n["unknown-author-trackingcat"] or "") end maxpos = maxpos + 1 out[maxpos] = label end return maxpos end --[=[-------------------------< G E T _ N A M E _ L I S T >---------------------------------------------------- get_name_list -- adapted from getAuthors code taken from Module:RexxS arguments: nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors; 'translator' for translators args - pointer to the parameter arguments table from the template call qid - value from |qid= parameter; the Q-id of the source (book, etc.) in qid wdl - value from the |wdl= parameter; a Boolean passed to enable links to Wikidata when no article exists returns nothing; modifies the args table ]=] local function get_name_list (nl_type, args, qid, wdl) local propertyID = "P50" local fallbackID = "P2093" -- author name string if nl_type =="author" then propertyID = 'P50' -- for authors fallbackID = 'P2093' -- author-string elseif nl_type =="editor" then propertyID = 'P5769' -- "editor-in-chief" fallbackID = 'P98' -- for editors - So-called "fallbacks" are actually a second set of properties processed -- TBD. Take book series editors into account as well (if they have a separate P code as well)? elseif nl_type == "translator" then propertyID = 'P655' -- for translators fallbackID = nil -- elseif 'contributor' == nl_type then -- f.e. author of forewords (P2679) and afterwords (P2680); requires |contribution=, |title= and |author= -- propertyID = 'P' -- for contributors -- fallbackID = nil else return -- not specified so return end -- wdl is a Boolean passed to enable links to Wikidata when no article exists -- if "false" or "no" or "0" is passed set it false -- if nothing or an empty string is passed set it false if wdl and (#wdl > 0) then wdl = wdl:lower() wdl = in_array (wdl, {"false", "no", "0"}) else -- wdl is empty, so wdl = false end local props = nil local fallback = nil if mw.wikibase.entityExists(qid) then props = mw.wikibase.getAllStatements(qid, propertyID) if props and fallbackID then fallback = mw.wikibase.getAllStatements(qid, fallbackID) end end -- Make sure it actually has at least one of the properties requested if not (props and props[1]) and not (fallback and fallback[1]) then return nil end -- So now we have something to return: -- table 'out' is going to store the names(s): -- and table 'link' will store any links to the name's article local out = {} local link = {} local maxpos = 0 if props and props[1] then for k, v in pairs(props) do maxpos = makelink(v, out, link, maxpos, wdl) end end if fallback and fallback[1] then -- second properties for k, v in pairs(fallback) do maxpos = makelink(v, out, link, maxpos, wdl) end end -- if there's anything to return, then insert the additions in the template arguments table -- in the form |author1=firstname secondname |author2= ... -- Renumber, in case we have inconsistent numbering local keys = {} for k, v in pairs(out) do keys[#keys + 1] = k end table.sort(keys) -- as they might be out of order for i, k in ipairs(keys) do out[k] = out[k]:gsub ('&#39;', '\''); -- prevent cs1|2 multiple names categorization; replace html entity with the actual character mw.log(i .. " " .. k .. " " .. (out[k])) if args[nl_type .. i] then -- name gets overwritten -- pull corresponding -link only if overwritten name is same as WD name if link[k] and (args[nl_type .. i] == out[k]) then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end else -- name does not get overwritten, so pull name from WD args[nl_type .. i] = out[k] if link[k] then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end end end end -- gets language codes used for a monolingual text property as a table function p._getLangOfProp(qid, pid) if not pid then return {} end local out = {} local props = mw.wikibase.getAllStatements(qid, pid) for i, v in ipairs(props) do if v.mainsnak.datatype == "monolingualtext" and v.mainsnak.datavalue then out[#out + 1] = v.mainsnak.datavalue.value.language end end return out end function p.getLangOfProp(frame) local pid = frame.args.pid or mw.text.trim(frame.args[1] or "") if pid == "" then return end local qid = frame.args.qid if qid == "" then qid = nil end return table.concat(p._getLangOfProp(qid, pid), ", ") end -- gets the language codes of a Wikidata entry as a table local function _lang_code(qid) local lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P424", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P218", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end return p._getLangOfProp(qid, "P1476") end function p.lang_code(frame) return table.concat(_lang_code(frame.args.qid or mw.text.trim(frame.args[1] or "")), ", ") end -- export for debug function p.getPropOfProp(frame) return getPropOfProp(frame.args) end -- wraps a string in nowiki unless disable flag is set local function wrap_nowiki(str, disable) if disable then return str or '' end return mw.text.nowiki(str or '') end -- sort sequence table whose values are key-value pairs by key local function comp_key(a, b) return a[1] < b[1] end -- sort sequence table whose values are key-value pairs by value local function comp_val(a, b) return a[2] < b[2] end --[[-------------------------< C I T E _ Q >------------------------------------------------------------------ Takes standard CS1|2 template parameters and passes all to {{citation}}. If neither of |author= and |author1= are set, calls get_authors() to try to get an author name-list from Wikidata. The result is passed to {{citation}} for rendering. --]] function p._cite_q (citeq_args) local frame = mw.getCurrentFrame() -- parameters that don't get passed to Citation local expand = citeq_args.expand -- when set to anything, causes {{cite q}} to render <code><nowiki>{{citation|...}}</nowiki></code> local qid = citeq_args.qid or citeq_args[1] local wdl = citeq_args.wdl local template = citeq_args.template citeq_args.expand = nil citeq_args[1] = nil citeq_args.qid = nil citeq_args.wdl = nil citeq_args.template = nil -- if title supplied, flag to not read html title local titleforced = (citeq_args.title ~= nil) local oth = {} -- put the language codes into a sequential table langcodes[] local langcodes = {} if citeq_args.language then -- check these are a supported language codes for lc in mw.text.gsplit( citeq_args.language, "[, ]+", false ) do langcodes[#langcodes+1] = mw.language.isSupportedLanguage(citeq_args.language) and citeq_args.language end end if not langcodes[1] then -- try to find language of work langcodes = _lang_code(qid) end if not langcodes[1] then -- try fallback to journal's language local journal_qid = followQid({qid = qid, props = "P1433"}) langcodes = journal_qid and _lang_code(journal_qid) end citeq_args.language = citeq_args.language or table.concat(langcodes, ", ") -- loop through list of simple properties and get their values in citeq_args for name, data in pairs(simple_properties) do citeq_args[name] = getValue( {data.id, fwd = "ALL", osd = "no", noicon = "true", qid = qid, maxvals = data.maxvals, linked = data.linked, rank = data.rank or "best", citeq_args[name] } ) if data.populate_from_journal then local publishedin = getValue( {"P1433", ps = 1, qid = qid, maxvals = 0, citeq_args[name], qual = data.id, qualsonly = 'yes'} ) citeq_args[name] = publishedin or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals = data.maxvals, ps = 1}) end if citeq_args[name] and citeq_args[name]:find('[[Category:缺少維基數據信息的條目]]', 1, true) then -- try fallback to work's native language citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = langcodes[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned -- try fallback to qid's native language local qid_languages = _lang_code(citeq_args[name]) citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = qid_languages[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned again citeq_args[name] = nil else -- record the language found if no lang specified citeq_args.language = citeq_args.language or qid_languages[1] end end end if data.others then oth[#oth + 1] = citeq_args[name] and (name:gsub("^%l", string.upper) .. ": " .. citeq_args[name]) citeq_args[name] = nil end end citeq_args.others = citeq_args.others or table.concat(oth, ". ") if citeq_args.others == "" then citeq_args.others = nil end citeq_args.journal = citeq_args.journal and citeq_args.journal:gsub("^''", ""):gsub("''$", ""):gsub("|''", "|"):gsub("'']]", "]]") citeq_args.ol = (getValue( {"P648", ps = 1, qid = qid, maxvals = 1, citeq_args.ol } ) or ''):gsub("^OL(.+)$", "%1") if citeq_args.ol == "" then citeq_args.ol = nil end -- TBD. Take care of |ol-access=? citeq_args.biorxiv = citeq_args.biorxiv and ("10.1101/" .. citeq_args.biorxiv) citeq_args.isbn = getValue( {"P957", ps = 1, qid = qid, maxvals = 1, rank="best", citeq_args.isbn } ) -- try ISBN 10 (only one value accepted) if citeq_args["publication-date"] then citeq_args["publication-date"] = mw.getCurrentFrame():expandTemplate { title = "ISOdate", args = {citeq_args["publication-date"]} } end -- if url then see if there's an archive: citeq_args.url local url if not citeq_args.url then for i, pr in ipairs( {"P953", "P856", "P2699"} ) do url = getValue( {pr, ps = 1, qid = qid, maxvals = 1, qual="P1065" } ) if url then citeq_args.url = mw.text.split( url, " (", true )[1] local arcurl = mw.ustring.match( url, " %((.*)%)" ) -- when there is an archive url, <url> holds: url<space>(archive url); here extract the archive url if present if arcurl then local arcy, arcm, arcd = arcurl:match("(20%d%d)%p?(%d%d)%p?(%d%d)") if arcy and arcm and arcd then citeq_args["archive-url"] = arcurl citeq_args["archive-date"] = tonumber(arcd) .. " " .. i18n.months[tonumber(arcm)] .. " " .. arcy end end break end end end if citeq_args.publisher == "Unknown" then -- look for "stated as" (P1932) local stated_as = getValue( {"P123", ps = 1, qid = qid, maxvals = 1, qual="P1932", qo="y"} ) if stated_as then citeq_args.publisher = stated_as end end if not titleforced then -- Handle subtitle. if citeq_args.title then local subtitle = mw.wikibase.getBestStatements (qid, 'P1680'); if 0 ~= #subtitle then subtitle = subtitle[1].mainsnak.datavalue.value.text; citeq_args.title = citeq_args.title .. ": " .. subtitle end end local htmltitle = getValue( {"P1476", qual = "P6833", ps = 1, qid = qid, maxvals = 1, qo = "y"} ) if htmltitle then citeq_args.title = htmltitle:gsub("</?i>", "''") else local title_display = citeq_args.title or mw.wikibase.getLabel(qid) or (langcodes[1] and mw.wikibase.getLabelByLang(qid, langcodes[1])) or ("No label or title -- debug: " .. qid) if citeq_args.url then citeq_args.title = wrap_nowiki(title_display) else local slink = mw.wikibase.getSitelink(qid, "zhwiki") local slink_flag = false local wrap_title = '' local wslink = false if not slink then -- See if we have wikisource if not citeq_args.url then local wikisource_sitelink = mw.wikibase.getSitelink(qid, "zhwikisource") or nil if wikisource_sitelink then slink = ':s:'..wikisource_sitelink wslink = true end end end if citeq_args.title then if slink then wrap_title = wrap_nowiki(citeq_args.title) slink_flag = true else citeq_args.title = wrap_nowiki(citeq_args.title) end else if slink and not wslink then if slink:lower() == title_display:lower() then citeq_args.title = '[[' .. slink .. ']]' else wrap_title = wrap_nowiki(slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")) slink_flag = true end elseif wslink then wrap_title = wrap_nowiki(title_display) slink_flag = true else citeq_args.title = wrap_nowiki(title_display) end end if slink_flag then if slink == wrap_title and not wslink then -- direct link citeq_args.title = '[[' .. slink .. ']]' else -- piped link citeq_args.title = '[[' .. slink .. '|' .. wrap_title .. ']]' end end end end end -- TBD: incorporate |at, |sheets= and |sheet= here as well -- Sort out what should happen if several of them are given at the same time if citeq_args.page or citeq_args.p then -- let single take precedence over multiple citeq_args.pages = nil citeq_args.pp = nil end if citeq_args.pages then local _, count = string.gsub(citeq_args.pages, "[,;%s]%d+", "") if count == 1 then citeq_args.page = citeq_args.pages citeq_args.pages = nil end end if is_set (qid) then if not is_set (citeq_args.author) and not is_set (citeq_args.author1) and not is_set (citeq_args.subject) and not is_set (citeq_args.subject1) and not is_set (citeq_args.host) and not is_set (citeq_args.host1) and not is_set (citeq_args.last) and not is_set (citeq_args.last1) and not is_set (citeq_args.surname) and not is_set (citeq_args.surname1) and not is_set (citeq_args['author-last']) and not is_set (citeq_args['author-last1']) and not is_set (citeq_args['author1-last']) and not is_set (citeq_args['author-surname']) and not is_set (citeq_args['author-surname1']) and not is_set (citeq_args['author1-surname1']) then -- if neither are set, try to get authors from Wikidata get_name_list ('author', citeq_args, qid, wdl) -- modify citeq_args table with authors from Wikidata end if not is_set (citeq_args.editor) and not is_set (citeq_args.editor1) and not is_set (citeq_args['editor-last']) and not is_set (citeq_args['editor-last1']) and not is_set (citeq_args['editor1-last']) and not is_set (citeq_args['editor-surname']) and not is_set (citeq_args['editor-surname1']) and not is_set (citeq_args['editor1-surname']) then -- if neither are set, try to get editors from Wikidata get_name_list ('editor', citeq_args, qid, wdl) -- modify citeq_args table with editors from Wikidata end if not is_set (citeq_args.translator) and not is_set (citeq_args.translator1) and not is_set (citeq_args['translator-last']) and not is_set (citeq_args['translator-last1']) and not is_set (citeq_args['translator1-last']) and not is_set (citeq_args['translator-surname']) and not is_set (citeq_args['translator-surname1']) and not is_set (citeq_args['translator1-surname']) then -- if neither are set, try to get translators from Wikidata get_name_list ('translator', citeq_args, qid, wdl) -- modify citeq_args table with translators from Wikidata end end for k, v in pairs(citeq_args) do if in_array (v, {'(())', 'unset', 'ignore'}) or 'string' ~= type(k) then -- empty accept-as-is-written (()) markup to indicate an empty/unused parameter value, other ((...)) markups are deliberately passed down to {{citation}} citeq_args[k] = nil elseif in_array (v, {'((unset))', '((ignore))'}) then -- strip off markup for free-text values clashing with local keywords citeq_args[k] = 'unset' end end local author_count = 0 for k, v in pairs(citeq_args) do if k:find("^author%d+$") then author_count = author_count + 1 end end if author_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-authors'] then citeq_args['display-authors'] = nil; -- unset because no longer needed else citeq_args['display-authors'] = citeq_args['display-authors'] or 3 -- limit to three displayed names end end local editor_count = 0 for k, v in pairs(citeq_args) do if k:find("^editor%d+$") then editor_count = editor_count + 1 end end if editor_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-editors'] then citeq_args['display-editors'] = nil; -- unset because no longer needed else citeq_args['display-editors'] = citeq_args['display-editors'] or 3 -- limit to three displayed names end end -- change edition to ordinal if it's set and numeric citeq_args.edition = citeq_args.edition and p.makeOrdinal(citeq_args.edition) -- code to make a guess what template to use from the supplied parameters -- (first draft for proof-of-concept) if citeq_args.isbn then template = template or "book" citeq_args.asin = nil -- suppress ASIN if ISBN exists elseif citeq_args.journal then template = template or "journal" elseif citeq_args.website then template = template or "web" end -- template is CS1 designator: journal, web, news, etc. if template then -- citeq_args.mode = citeq_args.mode or "cs1" -- a cs1 template already knows that it is cs1 so this line is superfluous template = "Cite " .. template else -- citeq_args.mode = citeq_args.mode or "cs2" -- a cs2 template already knows that it is cs2 so this line is superfluous template = "Citation" end -- |id= could hold more than one identifier pulled from Wikidata not supported by {{citation}}, right now only add our qid to the list local list_sep = '. ' if citeq_args.mode ~= 'cs1' then list_sep = ', ' end local id = '[[WDQ (标识符)|Wikidata]]&nbsp;[[:d:' .. qid .. '|' .. qid .. ']]' -- go through "WDQ (标识符)" redirect to reduce clutter in "链入页面" and improve reverse lookup. Keep in sync with {{QID}}. local old_id = citeq_args.id if wdl then -- show WD logo id = id .. '[[File:Wikidata-logo.svg|16px|alt=|link=]]' -- possibly replace by WD edit icon? end if is_set (old_id) then citeq_args.id = old_id .. list_sep .. id -- append to user-specified contents else citeq_args.id = id end -- clean up any blank parameters for k, v in pairs(citeq_args) do if v == "" then citeq_args[k] = nil end end -- if |expand=<anything>, write a nowiki'd version to see what the {{citation}} template call looks like if expand then local expand_args = { "{{" .. template } -- init with citation template if expand == "self" then citeq_args.id = old_id -- restore original |id= parameter expand_args = { "{{cite Q|" .. qid } -- expand to itself end -- make a sortable table and sort it by param name local sorttable = {} for param, val in pairs (citeq_args) do table.insert(sorttable, {param, val}) end table.sort(sorttable, comp_key) -- add contents to expand_args for idx, val in ipairs(sorttable) do table.insert(expand_args, val[1] .. '=' .. val[2]) end -- make the nowiki'd string and done return "<code>" .. table.concat (expand_args, ' |') .. "}}</code>" end local erratumid = getPropertyIDs( { "P2507", qid = qid, fwd = "ALL", osd = "no", rank = "best", maxvals = 1 } ) if erratumid then erratumid = " [[d:" .. erratumid .. "|(erratum)]]" .. "[[Category:Cite Q - 引用含勘误表的作品]]" else erratumid = "" end local opt_cat = '' if getValue( {"P5824", ps = 1, qid = qid} ) then opt_cat = '[[Category:Cite Q - 引用被撤稿的作品]]<!-- retracted -->' end if getValue( {"P1366", ps = 1, qid = qid} ) then opt_cat = opt_cat .. '[[Category:Cite Q - 引用被替换的作品]]<!-- replaced -->' end return frame:expandTemplate{title = template, args = citeq_args} .. erratumid .. opt_cat -- render the template end function p.cite_q (frame) local args = {} for k, v in pairs(frame:getParent().args) do if v ~= "" then args[k] = v end end -- From #invoke -- -- {{#property: will return values separated by MediaWiki:Comma-separator, -- which have a zero-width space to allow line wrap. -- However, Module:Citation/CS1/Configuration blacklisted invisible_chars, -- which include the zero-width space. -- To fix the unexpected warning message, simply replace them here should be -- the simplest way without breaking Special:ActiveLanguages on translatewiki -- and various places. -- Also, we need ", " instead of "、" for citations. for k, v in pairs(frame.args) do if v ~= "" then args[k] = string.gsub(v, "、​", ", " ) end end args.qid = args.qid or args[1] or "" if args.qid == "" then return nil end args[1] = nil local citesep = (args.citesep or "") if citesep == "" then citesep = ", " end citesep = citesep:gsub('"', '') -- strip double quotes after setting default to allow |citesep="" as a blank separator args.citesep = nil local tag = args.tag or "" if tag == "" then tag = nil end args.tag = nil local list = args.list or "" if list == "" then list = nil end args.list = nil args.language = args.language or args.lang args.lang = nil local cites = {} for q in args.qid:gmatch("Q%d+") do -- make a new copy of the arguments local newargs = {} for k, v in pairs(args) do if k ~= "qid" then newargs[k] = v end end newargs.qid = q if tag == "ref" then cites[#cites + 1] = frame:callParserFunction{ name = "#tag:ref", args = { p._cite_q(newargs), name = q } } -- expand like this: args = { p._cite_q(newargs), name = 'foo', group = 'bar' } else cites[#cites + 1] = p._cite_q(newargs) end end if list then return frame:expandTemplate{ title = list, args = cites } else return table.concat(cites, citesep) end end return p m6d8gil8shom0brozav7usth8gm4bae 43066 43052 2026-07-07T18:02:31Z 内存溢出的猫 7954 43066 Scribunto text/plain -- Version: 2021-10-19 local p = {} require('strict') local wdib = require('Module:WikidataIB/sandbox for Cite Q') local getValue = wdib._getValue local getPropOfProp = wdib._getPropOfProp local followQid = wdib._followQid local getPropertyIDs = wdib._getPropertyIDs local i18n = { ["unknown-author"] = mw.wikibase.getLabel("Q4233718"):gsub("^%l", mw.ustring.upper), ["unknown-author-trackingcat"] = "[[Category:Cite Q - bouxsij mbouj rox]]", ["ordinal"] = { [1] = "st", [2] = "nd", [3] = "rd", ["default"] = "th" }, ["months"] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, } ------------------------------------------------------------------------------- -- makeOrdinal needs to be internationalised along with the above i18n -- takes cardinal number as a numeric and returns the ordinal as a string -- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. ------------------------------------------------------------------------------- p.makeOrdinal = function(cardinal) local card = tonumber(cardinal) if not card then return cardinal end local ordsuffix = i18n.ordinal.default if card % 10 == 1 then ordsuffix = i18n.ordinal[1] elseif card % 10 == 2 then ordsuffix = i18n.ordinal[2] elseif card % 10 == 3 then ordsuffix = i18n.ordinal[3] end -- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' -- similarly for 12 and 13, etc. if (card % 100 == 11) or (card % 100 == 12) or (card % 100 == 13) then ordsuffix = i18n.ordinal.default end return card .. ordsuffix end -- Table of simple properties that can be fetched in roughly the same way: -- id = PXXX -- maxvals = maximum number of multiple values (0 for all) -- linked = "no" suppresses linking -- populate_from_journal = true/false determines whether to look in a journal where the source is published -- rank = "best", "preferred", normal, etc. determines how Wikidata ranks are treated -- others = true - the value for the property goes to "others" section local simple_properties = { publisher = {id = "P123", maxvals = 1}, oclc = {id = "P243", maxvals = 1}, ['publication-place'] = {id = "P291", maxvals = 0, linked = 'no'}, -- publication place (don't put into |place=; is treated specially in {{citation}} if both are given) doi = {id = "P356", maxvals = 1}, -- take care of |doi-broken-date= (WD "reason for deprecation"/"stated as") and |doi-access= (WD "access status")? issue = {id = "P433", maxvals = 0, populate_from_journal = true}, -- distinguish from |number= ("P1545"?) if both are given (still blocked by {{citation}}, but will be supported in the future) pmid = {id = "P698", maxvals = 1}, -- gbooks = {id = "P675", maxvals = 1}, -- to be added to {{citation}} -- ia = {id = "P724", maxvals = 1}, -- to be added to {{citation}} arxiv = {id = "P818", maxvals = 1}, bibcode = {id = "P819", maxvals = 1}, -- take care of |bibcode-access=? jstor = {id = "P888", maxvals = 1}, -- take care of |jstor-access=? mr = {id = "P889", maxvals = 1}, rfc = {id = "P892", maxvals = 1}, zbl = {id = "P894", maxvals = 1}, ssrn = {id = "P893", maxvals = 1}, place = {id = "P1071", maxvals = 0, linked = 'no'}, -- written-at place -- ['total-pages'] = {id = "P1104", maxvals = 0, linked = 'no'}, -- to be added to {{citation}} / COinS &rft.tpages= -- coden = {id = "P1159", maxvals = 1}, -- to be added to {{citation}} / COinS &rft.coden= s2cid = {id = "P8299", maxvals = 1}, -- take care of |s2cid-access=? pmc = {id = "P932", maxvals = 1}, -- take care of |pmc-embargo-date= (WD "reason for deprecation")? lccn = {id = "P1144", maxvals = 1}, hdl = {id = "P1184", maxvals = 1}, -- take care of |hdl-access=? ismn = {id = "P1208", maxvals = 1}, journal = {id = "P1433", maxvals = 1}, citeseerx = {id = "P3784", maxvals = 1}, osti = {id = "P3894", maxvals = 1}, -- take care of |osti-access=? biorxiv = {id = "P3951", maxvals = 1}, asin = {id = "P5749", maxvals = 1}, -- What about |asin-tld=? (WD examples resolve to .com at present, but may change) -- ['catalog-number'] = {id = "P528", maxvals = 0}, -- to be added to {{citation}} / COinS &rft.artnum= isbn = {id = "P212", maxvals = 1, populate_from_journal = true}, -- ISBN 13 issn = {id = "P236", maxvals = 1, populate_from_journal = true}, -- distinguish from |eissn= for electronic issues? -- jfm = {id = "P?", maxvals = 1}, -- Jahrbuch über die Fortschritte der Mathematik (not Zbl) -- sbn = {id = "P?", maxvals = 1}, -- Standard Book Number (predecessor of ISBN, not ICCU) -- message-id = {id = "P?", maxvals = 1}, -- Usenet message ID chapter = {id = "P792", maxvals = 1}, ['publication-date'] = {id = "P577", maxvals = 1, populate_from_journal = true}, -- publication date (don't use |date=; is treated specially in {{citation}} if both are given.) series = {id = "P179", maxvals = 1, populate_from_journal = true}, version = {id = "P348", maxvals = 0}, edition = {id = "P393", maxvals = 0}, volume = {id = "P478", maxvals = 0, populate_from_journal = true}, -- part = {id = "P1545"?, maxvals = 0}, -- to be added to {{citation}} / COinS &rft.part= title = {id = "P1476", rank="p n"}, -- url = {id = "P953", maxvals = 1}, -- deal with this along with archive-url pages = {id = "P304", maxvals = 0, populate_from_journal = true}, at = {id = "P958", maxvals = 0, populate_from_journal = true}, -- also incorporate lines (P7421) and columns (P3903) into this (cite map also supports |section=) -- sheets = {id = "P7416", maxvals = 0, populate_from_journal = true}, -- interviewer = {id = "P?", maxvals = 0}, -- does **not** go to "others" section! Multiple interviewers should be n-enumerated illustrator = {id = "P110", maxvals = 10, others = true}, -- goes to "others" section -- foreword and afterword, when contributions to another author's work, are contributions so belong in |contribution=; -- the writer's name goes in |contributor=; requires |title= and |author= -- However, this might need to add support for multiple contributors and their roles to {{citation}}, see Help_talk:Citation_Style_1#Others -- foreword = {id = "P2679", maxvals = 10, others = true}, -- goes to "others" section -- afterword = {id = "P2680", maxvals = 10, others = true}, -- goes to "others" section composer = {id = "P86", maxvals = 10, others = true}, -- goes to "others" section animator = {id = "P6942", maxvals = 10, others = true}, -- goes to "others" section director = {id = "P57", maxvals = 10, others = true}, -- goes to "others" section screenwriter = {id = "P58", maxvals = 10, others = true}, -- goes to "others" section signatory = {id = "P1891", maxvals = 10, others = true}, -- goes to "others" section presenter = {id = "P371", maxvals = 10, others = true}, -- goes to "others" section performer = {id = "P175", maxvals = 10, others = true}, -- goes to "others" section } --[[--------------------------< 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 _ A R R A Y >-------------------------------------------------------------- Whether needle is in haystack (taken from Module:Citation/CS1/Utilities) ]] 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 --[[--------------------------< A C C E P T _ V A L U E >------------------------------------------------------- Accept WD value by framing in ((...)) if param_val is equal to keyword; else pass-through WD value as is. ]] local function accept_value( param_val, wd_val ) local val = param_val if val then if in_array (val, {'accept', '))((', ':d:'}) then val = '((' .. wd_val .. '))' elseif '((accept))' == val then val = 'accept' elseif '(())(())' == val then val = '))((' elseif '((:d:))' == val then val = ':d:' else val = wd_val end end return val end -- function to fetch a value to display local function makelink(v, out, link, maxpos, wdl) local label if v.mainsnak.snaktype == "value" then if v.mainsnak.datatype == "wikibase-item" then local qnumber = v.mainsnak.datavalue.value.id local sitelink = mw.wikibase.getSitelink(qnumber) if qnumber == "Q2818964" then sitelink = nil end -- suppress link to "Various authors" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = mw.wikibase.getLabel(qnumber) if label then label = mw.text.nowiki(label) else label = qnumber -- should add tracking category end end local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) if sitelink then -- just the plain name, -- but keep a record of the links, using the same index out[position] = label link[position] = sitelink else if wdl then -- show that there's a Wikidata entry available out[position] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]&nbsp;<span title='" .. i18n["errors"]["local-article-not-found"] .. "'>[[File:Wikidata-logo.svg|16px|alt=|link=]]</span>" else -- no Wikidata links wanted, so just give the plain label out[position] = label end end elseif v.mainsnak.datatype == "string" then local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) out[position] = v.mainsnak.datavalue.value else -- not a wikibase-item or a string! end else -- code here if we want to return something when author is "unknown" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = i18n["unknown-author"] .. (i18n["unknown-author-trackingcat"] or "") end maxpos = maxpos + 1 out[maxpos] = label end return maxpos end --[=[-------------------------< G E T _ N A M E _ L I S T >---------------------------------------------------- get_name_list -- adapted from getAuthors code taken from Module:RexxS arguments: nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors; 'translator' for translators args - pointer to the parameter arguments table from the template call qid - value from |qid= parameter; the Q-id of the source (book, etc.) in qid wdl - value from the |wdl= parameter; a Boolean passed to enable links to Wikidata when no article exists returns nothing; modifies the args table ]=] local function get_name_list (nl_type, args, qid, wdl) local propertyID = "P50" local fallbackID = "P2093" -- author name string if nl_type =="author" then propertyID = 'P50' -- for authors fallbackID = 'P2093' -- author-string elseif nl_type =="editor" then propertyID = 'P5769' -- "editor-in-chief" fallbackID = 'P98' -- for editors - So-called "fallbacks" are actually a second set of properties processed -- TBD. Take book series editors into account as well (if they have a separate P code as well)? elseif nl_type == "translator" then propertyID = 'P655' -- for translators fallbackID = nil -- elseif 'contributor' == nl_type then -- f.e. author of forewords (P2679) and afterwords (P2680); requires |contribution=, |title= and |author= -- propertyID = 'P' -- for contributors -- fallbackID = nil else return -- not specified so return end -- wdl is a Boolean passed to enable links to Wikidata when no article exists -- if "false" or "no" or "0" is passed set it false -- if nothing or an empty string is passed set it false if wdl and (#wdl > 0) then wdl = wdl:lower() wdl = in_array (wdl, {"false", "no", "0"}) else -- wdl is empty, so wdl = false end local props = nil local fallback = nil if mw.wikibase.entityExists(qid) then props = mw.wikibase.getAllStatements(qid, propertyID) if props and fallbackID then fallback = mw.wikibase.getAllStatements(qid, fallbackID) end end -- Make sure it actually has at least one of the properties requested if not (props and props[1]) and not (fallback and fallback[1]) then return nil end -- So now we have something to return: -- table 'out' is going to store the names(s): -- and table 'link' will store any links to the name's article local out = {} local link = {} local maxpos = 0 if props and props[1] then for k, v in pairs(props) do maxpos = makelink(v, out, link, maxpos, wdl) end end if fallback and fallback[1] then -- second properties for k, v in pairs(fallback) do maxpos = makelink(v, out, link, maxpos, wdl) end end -- if there's anything to return, then insert the additions in the template arguments table -- in the form |author1=firstname secondname |author2= ... -- Renumber, in case we have inconsistent numbering local keys = {} for k, v in pairs(out) do keys[#keys + 1] = k end table.sort(keys) -- as they might be out of order for i, k in ipairs(keys) do out[k] = out[k]:gsub ('&#39;', '\''); -- prevent cs1|2 multiple names categorization; replace html entity with the actual character mw.log(i .. " " .. k .. " " .. (out[k])) if args[nl_type .. i] then -- name gets overwritten -- pull corresponding -link only if overwritten name is same as WD name if link[k] and (args[nl_type .. i] == out[k]) then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end else -- name does not get overwritten, so pull name from WD args[nl_type .. i] = out[k] if link[k] then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end end end end -- gets language codes used for a monolingual text property as a table function p._getLangOfProp(qid, pid) if not pid then return {} end local out = {} local props = mw.wikibase.getAllStatements(qid, pid) for i, v in ipairs(props) do if v.mainsnak.datatype == "monolingualtext" and v.mainsnak.datavalue then out[#out + 1] = v.mainsnak.datavalue.value.language end end return out end function p.getLangOfProp(frame) local pid = frame.args.pid or mw.text.trim(frame.args[1] or "") if pid == "" then return end local qid = frame.args.qid if qid == "" then qid = nil end return table.concat(p._getLangOfProp(qid, pid), ", ") end -- gets the language codes of a Wikidata entry as a table local function _lang_code(qid) local lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P424", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P218", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end return p._getLangOfProp(qid, "P1476") end function p.lang_code(frame) return table.concat(_lang_code(frame.args.qid or mw.text.trim(frame.args[1] or "")), ", ") end -- export for debug function p.getPropOfProp(frame) return getPropOfProp(frame.args) end -- wraps a string in nowiki unless disable flag is set local function wrap_nowiki(str, disable) if disable then return str or '' end return mw.text.nowiki(str or '') end -- sort sequence table whose values are key-value pairs by key local function comp_key(a, b) return a[1] < b[1] end -- sort sequence table whose values are key-value pairs by value local function comp_val(a, b) return a[2] < b[2] end --[[-------------------------< C I T E _ Q >------------------------------------------------------------------ Takes standard CS1|2 template parameters and passes all to {{citation}}. If neither of |author= and |author1= are set, calls get_authors() to try to get an author name-list from Wikidata. The result is passed to {{citation}} for rendering. --]] function p._cite_q (citeq_args) local frame = mw.getCurrentFrame() -- parameters that don't get passed to Citation local expand = citeq_args.expand -- when set to anything, causes {{cite q}} to render <code><nowiki>{{citation|...}}</nowiki></code> local qid = citeq_args.qid or citeq_args[1] local wdl = citeq_args.wdl local template = citeq_args.template citeq_args.expand = nil citeq_args[1] = nil citeq_args.qid = nil citeq_args.wdl = nil citeq_args.template = nil -- if title supplied, flag to not read html title local titleforced = (citeq_args.title ~= nil) local oth = {} -- put the language codes into a sequential table langcodes[] local langcodes = {} if citeq_args.language then -- check these are a supported language codes for lc in mw.text.gsplit( citeq_args.language, "[, ]+", false ) do langcodes[#langcodes+1] = mw.language.isSupportedLanguage(citeq_args.language) and citeq_args.language end end if not langcodes[1] then -- try to find language of work langcodes = _lang_code(qid) end if not langcodes[1] then -- try fallback to journal's language local journal_qid = followQid({qid = qid, props = "P1433"}) langcodes = journal_qid and _lang_code(journal_qid) end citeq_args.language = citeq_args.language or table.concat(langcodes, ", ") -- loop through list of simple properties and get their values in citeq_args for name, data in pairs(simple_properties) do citeq_args[name] = getValue( {data.id, fwd = "ALL", osd = "no", noicon = "true", qid = qid, maxvals = data.maxvals, linked = data.linked, rank = data.rank or "best", citeq_args[name] } ) if data.populate_from_journal then local publishedin = getValue( {"P1433", ps = 1, qid = qid, maxvals = 0, citeq_args[name], qual = data.id, qualsonly = 'yes'} ) citeq_args[name] = publishedin or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals = data.maxvals, ps = 1}) end if citeq_args[name] and citeq_args[name]:find('[[Category:缺少維基數據信息的條目]]', 1, true) then -- try fallback to work's native language citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = langcodes[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned -- try fallback to qid's native language local qid_languages = _lang_code(citeq_args[name]) citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = qid_languages[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned again citeq_args[name] = nil else -- record the language found if no lang specified citeq_args.language = citeq_args.language or qid_languages[1] end end end if data.others then oth[#oth + 1] = citeq_args[name] and (name:gsub("^%l", string.upper) .. ": " .. citeq_args[name]) citeq_args[name] = nil end end citeq_args.others = citeq_args.others or table.concat(oth, ". ") if citeq_args.others == "" then citeq_args.others = nil end citeq_args.journal = citeq_args.journal and citeq_args.journal:gsub("^''", ""):gsub("''$", ""):gsub("|''", "|"):gsub("'']]", "]]") citeq_args.ol = (getValue( {"P648", ps = 1, qid = qid, maxvals = 1, citeq_args.ol } ) or ''):gsub("^OL(.+)$", "%1") if citeq_args.ol == "" then citeq_args.ol = nil end -- TBD. Take care of |ol-access=? citeq_args.biorxiv = citeq_args.biorxiv and ("10.1101/" .. citeq_args.biorxiv) citeq_args.isbn = getValue( {"P957", ps = 1, qid = qid, maxvals = 1, rank="best", citeq_args.isbn } ) -- try ISBN 10 (only one value accepted) if citeq_args["publication-date"] then citeq_args["publication-date"] = mw.getCurrentFrame():expandTemplate { title = "ISOdate", args = {citeq_args["publication-date"]} } end -- if url then see if there's an archive: citeq_args.url local url if not citeq_args.url then for i, pr in ipairs( {"P953", "P856", "P2699"} ) do url = getValue( {pr, ps = 1, qid = qid, maxvals = 1, qual="P1065" } ) if url then citeq_args.url = mw.text.split( url, " (", true )[1] local arcurl = mw.ustring.match( url, " %((.*)%)" ) -- when there is an archive url, <url> holds: url<space>(archive url); here extract the archive url if present if arcurl then local arcy, arcm, arcd = arcurl:match("(20%d%d)%p?(%d%d)%p?(%d%d)") if arcy and arcm and arcd then citeq_args["archive-url"] = arcurl citeq_args["archive-date"] = tonumber(arcd) .. " " .. i18n.months[tonumber(arcm)] .. " " .. arcy end end break end end end if citeq_args.publisher == "Unknown" then -- look for "stated as" (P1932) local stated_as = getValue( {"P123", ps = 1, qid = qid, maxvals = 1, qual="P1932", qo="y"} ) if stated_as then citeq_args.publisher = stated_as end end if not titleforced then -- Handle subtitle. if citeq_args.title then local subtitle = mw.wikibase.getBestStatements (qid, 'P1680'); if 0 ~= #subtitle then subtitle = subtitle[1].mainsnak.datavalue.value.text; citeq_args.title = citeq_args.title .. ": " .. subtitle end end local htmltitle = getValue( {"P1476", qual = "P6833", ps = 1, qid = qid, maxvals = 1, qo = "y"} ) if htmltitle then citeq_args.title = htmltitle:gsub("</?i>", "''") else local title_display = citeq_args.title or mw.wikibase.getLabel(qid) or (langcodes[1] and mw.wikibase.getLabelByLang(qid, langcodes[1])) or ("No label or title -- debug: " .. qid) if citeq_args.url then citeq_args.title = wrap_nowiki(title_display) else local slink = mw.wikibase.getSitelink(qid, "zhwiki") local slink_flag = false local wrap_title = '' local wslink = false if not slink then -- See if we have wikisource if not citeq_args.url then local wikisource_sitelink = mw.wikibase.getSitelink(qid, "zhwikisource") or nil if wikisource_sitelink then slink = ':s:'..wikisource_sitelink wslink = true end end end if citeq_args.title then if slink then wrap_title = wrap_nowiki(citeq_args.title) slink_flag = true else citeq_args.title = wrap_nowiki(citeq_args.title) end else if slink and not wslink then if slink:lower() == title_display:lower() then citeq_args.title = '[[' .. slink .. ']]' else wrap_title = wrap_nowiki(slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")) slink_flag = true end elseif wslink then wrap_title = wrap_nowiki(title_display) slink_flag = true else citeq_args.title = wrap_nowiki(title_display) end end if slink_flag then if slink == wrap_title and not wslink then -- direct link citeq_args.title = '[[' .. slink .. ']]' else -- piped link citeq_args.title = '[[' .. slink .. '|' .. wrap_title .. ']]' end end end end end -- TBD: incorporate |at, |sheets= and |sheet= here as well -- Sort out what should happen if several of them are given at the same time if citeq_args.page or citeq_args.p then -- let single take precedence over multiple citeq_args.pages = nil citeq_args.pp = nil end if citeq_args.pages then local _, count = string.gsub(citeq_args.pages, "[,;%s]%d+", "") if count == 1 then citeq_args.page = citeq_args.pages citeq_args.pages = nil end end if is_set (qid) then if not is_set (citeq_args.author) and not is_set (citeq_args.author1) and not is_set (citeq_args.subject) and not is_set (citeq_args.subject1) and not is_set (citeq_args.host) and not is_set (citeq_args.host1) and not is_set (citeq_args.last) and not is_set (citeq_args.last1) and not is_set (citeq_args.surname) and not is_set (citeq_args.surname1) and not is_set (citeq_args['author-last']) and not is_set (citeq_args['author-last1']) and not is_set (citeq_args['author1-last']) and not is_set (citeq_args['author-surname']) and not is_set (citeq_args['author-surname1']) and not is_set (citeq_args['author1-surname1']) then -- if neither are set, try to get authors from Wikidata get_name_list ('author', citeq_args, qid, wdl) -- modify citeq_args table with authors from Wikidata end if not is_set (citeq_args.editor) and not is_set (citeq_args.editor1) and not is_set (citeq_args['editor-last']) and not is_set (citeq_args['editor-last1']) and not is_set (citeq_args['editor1-last']) and not is_set (citeq_args['editor-surname']) and not is_set (citeq_args['editor-surname1']) and not is_set (citeq_args['editor1-surname']) then -- if neither are set, try to get editors from Wikidata get_name_list ('editor', citeq_args, qid, wdl) -- modify citeq_args table with editors from Wikidata end if not is_set (citeq_args.translator) and not is_set (citeq_args.translator1) and not is_set (citeq_args['translator-last']) and not is_set (citeq_args['translator-last1']) and not is_set (citeq_args['translator1-last']) and not is_set (citeq_args['translator-surname']) and not is_set (citeq_args['translator-surname1']) and not is_set (citeq_args['translator1-surname']) then -- if neither are set, try to get translators from Wikidata get_name_list ('translator', citeq_args, qid, wdl) -- modify citeq_args table with translators from Wikidata end end for k, v in pairs(citeq_args) do if in_array (v, {'(())', 'unset', 'ignore'}) or 'string' ~= type(k) then -- empty accept-as-is-written (()) markup to indicate an empty/unused parameter value, other ((...)) markups are deliberately passed down to {{citation}} citeq_args[k] = nil elseif in_array (v, {'((unset))', '((ignore))'}) then -- strip off markup for free-text values clashing with local keywords citeq_args[k] = 'unset' end end local author_count = 0 for k, v in pairs(citeq_args) do if k:find("^author%d+$") then author_count = author_count + 1 end end if author_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-authors'] then citeq_args['display-authors'] = nil; -- unset because no longer needed else citeq_args['display-authors'] = citeq_args['display-authors'] or 3 -- limit to three displayed names end end local editor_count = 0 for k, v in pairs(citeq_args) do if k:find("^editor%d+$") then editor_count = editor_count + 1 end end if editor_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-editors'] then citeq_args['display-editors'] = nil; -- unset because no longer needed else citeq_args['display-editors'] = citeq_args['display-editors'] or 3 -- limit to three displayed names end end -- change edition to ordinal if it's set and numeric citeq_args.edition = citeq_args.edition and p.makeOrdinal(citeq_args.edition) -- code to make a guess what template to use from the supplied parameters -- (first draft for proof-of-concept) if citeq_args.isbn then template = template or "book" citeq_args.asin = nil -- suppress ASIN if ISBN exists elseif citeq_args.journal then template = template or "journal" elseif citeq_args.website then template = template or "web" end -- template is CS1 designator: journal, web, news, etc. if template then -- citeq_args.mode = citeq_args.mode or "cs1" -- a cs1 template already knows that it is cs1 so this line is superfluous template = "Cite " .. template else -- citeq_args.mode = citeq_args.mode or "cs2" -- a cs2 template already knows that it is cs2 so this line is superfluous template = "Citation" end -- |id= could hold more than one identifier pulled from Wikidata not supported by {{citation}}, right now only add our qid to the list local list_sep = '. ' if citeq_args.mode ~= 'cs1' then list_sep = ', ' end local id = '[[WDQ (标识符)|Wikidata]]&nbsp;[[:d:' .. qid .. '|' .. qid .. ']]' -- go through "WDQ (标识符)" redirect to reduce clutter in "链入页面" and improve reverse lookup. Keep in sync with {{QID}}. local old_id = citeq_args.id if wdl then -- show WD logo id = id .. '[[File:Wikidata-logo.svg|16px|alt=|link=]]' -- possibly replace by WD edit icon? end if is_set (old_id) then citeq_args.id = old_id .. list_sep .. id -- append to user-specified contents else citeq_args.id = id end -- clean up any blank parameters for k, v in pairs(citeq_args) do if v == "" then citeq_args[k] = nil end end -- if |expand=<anything>, write a nowiki'd version to see what the {{citation}} template call looks like if expand then local expand_args = { "{{" .. template } -- init with citation template if expand == "self" then citeq_args.id = old_id -- restore original |id= parameter expand_args = { "{{cite Q|" .. qid } -- expand to itself end -- make a sortable table and sort it by param name local sorttable = {} for param, val in pairs (citeq_args) do table.insert(sorttable, {param, val}) end table.sort(sorttable, comp_key) -- add contents to expand_args for idx, val in ipairs(sorttable) do table.insert(expand_args, val[1] .. '=' .. val[2]) end -- make the nowiki'd string and done return "<code>" .. table.concat (expand_args, ' |') .. "}}</code>" end local erratumid = getPropertyIDs( { "P2507", qid = qid, fwd = "ALL", osd = "no", rank = "best", maxvals = 1 } ) if erratumid then erratumid = " [[d:" .. erratumid .. "|(erratum)]]" .. "[[Category:Cite Q - 引用含勘误表的作品]]" else erratumid = "" end local opt_cat = '' if getValue( {"P5824", ps = 1, qid = qid} ) then opt_cat = '[[Category:Cite Q - 引用被撤稿的作品]]<!-- retracted -->' end if getValue( {"P1366", ps = 1, qid = qid} ) then opt_cat = opt_cat .. '[[Category:Cite Q - 引用被替换的作品]]<!-- replaced -->' end return frame:expandTemplate{title = template, args = citeq_args} .. erratumid .. opt_cat -- render the template end function p.cite_q (frame) local args = {} for k, v in pairs(frame:getParent().args) do if v ~= "" then args[k] = v end end -- From #invoke -- -- {{#property: will return values separated by MediaWiki:Comma-separator, -- which have a zero-width space to allow line wrap. -- However, Module:Citation/CS1/Configuration blacklisted invisible_chars, -- which include the zero-width space. -- To fix the unexpected warning message, simply replace them here should be -- the simplest way without breaking Special:ActiveLanguages on translatewiki -- and various places. -- Also, we need ", " instead of "、" for citations. for k, v in pairs(frame.args) do if v ~= "" then args[k] = string.gsub(v, "、​", ", " ) end end args.qid = args.qid or args[1] or "" if args.qid == "" then return nil end args[1] = nil local citesep = (args.citesep or "") if citesep == "" then citesep = ", " end citesep = citesep:gsub('"', '') -- strip double quotes after setting default to allow |citesep="" as a blank separator args.citesep = nil local tag = args.tag or "" if tag == "" then tag = nil end args.tag = nil local list = args.list or "" if list == "" then list = nil end args.list = nil args.language = args.language or args.lang args.lang = nil local cites = {} for q in args.qid:gmatch("Q%d+") do -- make a new copy of the arguments local newargs = {} for k, v in pairs(args) do if k ~= "qid" then newargs[k] = v end end newargs.qid = q if tag == "ref" then cites[#cites + 1] = frame:callParserFunction{ name = "#tag:ref", args = { p._cite_q(newargs), name = q } } -- expand like this: args = { p._cite_q(newargs), name = 'foo', group = 'bar' } else cites[#cites + 1] = p._cite_q(newargs) end end if list then return frame:expandTemplate{ title = list, args = cites } else return table.concat(cites, citesep) end end return p lagdh8tr47ztndamak7dfixqi9820f7 43067 43066 2026-07-07T18:09:44Z 内存溢出的猫 7954 43067 Scribunto text/plain -- Version: 2021-10-19 local p = {} require('strict') local wdib = require('Module:WikidataIB/sandbox for Cite Q') local getValue = wdib._getValue local getPropOfProp = wdib._getPropOfProp local followQid = wdib._followQid local getPropertyIDs = wdib._getPropertyIDs local i18n = { ["unknown-author"] = mw.wikibase.getLabel("Q4233718"):gsub("^%l", mw.ustring.upper), ["unknown-author-trackingcat"] = "[[Category:Cite Q - bouxsij mbouj rox]]", ["ordinal"] = { [1] = "st", [2] = "nd", [3] = "rd", ["default"] = "th" }, ["months"] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, } ------------------------------------------------------------------------------- -- makeOrdinal needs to be internationalised along with the above i18n -- takes cardinal number as a numeric and returns the ordinal as a string -- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. ------------------------------------------------------------------------------- p.makeOrdinal = function(cardinal) local card = tonumber(cardinal) if not card then return cardinal end local ordsuffix = i18n.ordinal.default if card % 10 == 1 then ordsuffix = i18n.ordinal[1] elseif card % 10 == 2 then ordsuffix = i18n.ordinal[2] elseif card % 10 == 3 then ordsuffix = i18n.ordinal[3] end -- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' -- similarly for 12 and 13, etc. if (card % 100 == 11) or (card % 100 == 12) or (card % 100 == 13) then ordsuffix = i18n.ordinal.default end return card .. ordsuffix end -- Table of simple properties that can be fetched in roughly the same way: -- id = PXXX -- maxvals = maximum number of multiple values (0 for all) -- linked = "no" suppresses linking -- populate_from_journal = true/false determines whether to look in a journal where the source is published -- rank = "best", "preferred", normal, etc. determines how Wikidata ranks are treated -- others = true - the value for the property goes to "others" section local simple_properties = { publisher = {id = "P123", maxvals = 1}, oclc = {id = "P243", maxvals = 1}, ['publication-place'] = {id = "P291", maxvals = 0, linked = 'no'}, -- publication place (don't put into |place=; is treated specially in {{citation}} if both are given) doi = {id = "P356", maxvals = 1}, -- take care of |doi-broken-date= (WD "reason for deprecation"/"stated as") and |doi-access= (WD "access status")? issue = {id = "P433", maxvals = 0, populate_from_journal = true}, -- distinguish from |number= ("P1545"?) if both are given (still blocked by {{citation}}, but will be supported in the future) pmid = {id = "P698", maxvals = 1}, -- gbooks = {id = "P675", maxvals = 1}, -- to be added to {{citation}} -- ia = {id = "P724", maxvals = 1}, -- to be added to {{citation}} arxiv = {id = "P818", maxvals = 1}, bibcode = {id = "P819", maxvals = 1}, -- take care of |bibcode-access=? jstor = {id = "P888", maxvals = 1}, -- take care of |jstor-access=? mr = {id = "P889", maxvals = 1}, rfc = {id = "P892", maxvals = 1}, zbl = {id = "P894", maxvals = 1}, ssrn = {id = "P893", maxvals = 1}, place = {id = "P1071", maxvals = 0, linked = 'no'}, -- written-at place -- ['total-pages'] = {id = "P1104", maxvals = 0, linked = 'no'}, -- to be added to {{citation}} / COinS &rft.tpages= -- coden = {id = "P1159", maxvals = 1}, -- to be added to {{citation}} / COinS &rft.coden= s2cid = {id = "P8299", maxvals = 1}, -- take care of |s2cid-access=? pmc = {id = "P932", maxvals = 1}, -- take care of |pmc-embargo-date= (WD "reason for deprecation")? lccn = {id = "P1144", maxvals = 1}, hdl = {id = "P1184", maxvals = 1}, -- take care of |hdl-access=? ismn = {id = "P1208", maxvals = 1}, journal = {id = "P1433", maxvals = 1}, citeseerx = {id = "P3784", maxvals = 1}, osti = {id = "P3894", maxvals = 1}, -- take care of |osti-access=? biorxiv = {id = "P3951", maxvals = 1}, asin = {id = "P5749", maxvals = 1}, -- What about |asin-tld=? (WD examples resolve to .com at present, but may change) -- ['catalog-number'] = {id = "P528", maxvals = 0}, -- to be added to {{citation}} / COinS &rft.artnum= isbn = {id = "P212", maxvals = 1, populate_from_journal = true}, -- ISBN 13 issn = {id = "P236", maxvals = 1, populate_from_journal = true}, -- distinguish from |eissn= for electronic issues? -- jfm = {id = "P?", maxvals = 1}, -- Jahrbuch über die Fortschritte der Mathematik (not Zbl) -- sbn = {id = "P?", maxvals = 1}, -- Standard Book Number (predecessor of ISBN, not ICCU) -- message-id = {id = "P?", maxvals = 1}, -- Usenet message ID chapter = {id = "P792", maxvals = 1}, ['publication-date'] = {id = "P577", maxvals = 1, populate_from_journal = true}, -- publication date (don't use |date=; is treated specially in {{citation}} if both are given.) series = {id = "P179", maxvals = 1, populate_from_journal = true}, version = {id = "P348", maxvals = 0}, edition = {id = "P393", maxvals = 0}, volume = {id = "P478", maxvals = 0, populate_from_journal = true}, -- part = {id = "P1545"?, maxvals = 0}, -- to be added to {{citation}} / COinS &rft.part= title = {id = "P1476", rank="p n"}, -- url = {id = "P953", maxvals = 1}, -- deal with this along with archive-url pages = {id = "P304", maxvals = 0, populate_from_journal = true}, at = {id = "P958", maxvals = 0, populate_from_journal = true}, -- also incorporate lines (P7421) and columns (P3903) into this (cite map also supports |section=) -- sheets = {id = "P7416", maxvals = 0, populate_from_journal = true}, -- interviewer = {id = "P?", maxvals = 0}, -- does **not** go to "others" section! Multiple interviewers should be n-enumerated illustrator = {id = "P110", maxvals = 10, others = true}, -- goes to "others" section -- foreword and afterword, when contributions to another author's work, are contributions so belong in |contribution=; -- the writer's name goes in |contributor=; requires |title= and |author= -- However, this might need to add support for multiple contributors and their roles to {{citation}}, see Help_talk:Citation_Style_1#Others -- foreword = {id = "P2679", maxvals = 10, others = true}, -- goes to "others" section -- afterword = {id = "P2680", maxvals = 10, others = true}, -- goes to "others" section composer = {id = "P86", maxvals = 10, others = true}, -- goes to "others" section animator = {id = "P6942", maxvals = 10, others = true}, -- goes to "others" section director = {id = "P57", maxvals = 10, others = true}, -- goes to "others" section screenwriter = {id = "P58", maxvals = 10, others = true}, -- goes to "others" section signatory = {id = "P1891", maxvals = 10, others = true}, -- goes to "others" section presenter = {id = "P371", maxvals = 10, others = true}, -- goes to "others" section performer = {id = "P175", maxvals = 10, others = true}, -- goes to "others" section } --[[--------------------------< 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 _ A R R A Y >-------------------------------------------------------------- Whether needle is in haystack (taken from Module:Citation/CS1/Utilities) ]] 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 --[[--------------------------< A C C E P T _ V A L U E >------------------------------------------------------- Accept WD value by framing in ((...)) if param_val is equal to keyword; else pass-through WD value as is. ]] local function accept_value( param_val, wd_val ) local val = param_val if val then if in_array (val, {'accept', '))((', ':d:'}) then val = '((' .. wd_val .. '))' elseif '((accept))' == val then val = 'accept' elseif '(())(())' == val then val = '))((' elseif '((:d:))' == val then val = ':d:' else val = wd_val end end return val end -- function to fetch a value to display local function makelink(v, out, link, maxpos, wdl) local label if v.mainsnak.snaktype == "value" then if v.mainsnak.datatype == "wikibase-item" then local qnumber = v.mainsnak.datavalue.value.id local sitelink = mw.wikibase.getSitelink(qnumber) if qnumber == "Q2818964" then sitelink = nil end -- suppress link to "Various authors" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = mw.wikibase.getLabel(qnumber) if label then label = mw.text.nowiki(label) else label = qnumber -- should add tracking category end end local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) if sitelink then -- just the plain name, -- but keep a record of the links, using the same index out[position] = label link[position] = sitelink else if wdl then -- show that there's a Wikidata entry available out[position] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]&nbsp;<span title='" .. i18n["errors"]["local-article-not-found"] .. "'>[[File:Wikidata-logo.svg|16px|alt=|link=]]</span>" else -- no Wikidata links wanted, so just give the plain label out[position] = label end end elseif v.mainsnak.datatype == "string" then local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) out[position] = v.mainsnak.datavalue.value else -- not a wikibase-item or a string! end else -- code here if we want to return something when author is "unknown" if v.qualifiers and v.qualifiers.P1932 then label = v.qualifiers.P1932[1].datavalue.value elseif v.qualifiers and v.qualifiers.P1810 then label = v.qualifiers.P1810[1].datavalue.value else label = i18n["unknown-author"] .. (i18n["unknown-author-trackingcat"] or "") end maxpos = maxpos + 1 out[maxpos] = label end return maxpos end --[=[-------------------------< G E T _ N A M E _ L I S T >---------------------------------------------------- get_name_list -- adapted from getAuthors code taken from Module:RexxS arguments: nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors; 'translator' for translators args - pointer to the parameter arguments table from the template call qid - value from |qid= parameter; the Q-id of the source (book, etc.) in qid wdl - value from the |wdl= parameter; a Boolean passed to enable links to Wikidata when no article exists returns nothing; modifies the args table ]=] local function get_name_list (nl_type, args, qid, wdl) local propertyID = "P50" local fallbackID = "P2093" -- author name string if nl_type =="author" then propertyID = 'P50' -- for authors fallbackID = 'P2093' -- author-string elseif nl_type =="editor" then propertyID = 'P5769' -- "editor-in-chief" fallbackID = 'P98' -- for editors - So-called "fallbacks" are actually a second set of properties processed -- TBD. Take book series editors into account as well (if they have a separate P code as well)? elseif nl_type == "translator" then propertyID = 'P655' -- for translators fallbackID = nil -- elseif 'contributor' == nl_type then -- f.e. author of forewords (P2679) and afterwords (P2680); requires |contribution=, |title= and |author= -- propertyID = 'P' -- for contributors -- fallbackID = nil else return -- not specified so return end -- wdl is a Boolean passed to enable links to Wikidata when no article exists -- if "false" or "no" or "0" is passed set it false -- if nothing or an empty string is passed set it false if wdl and (#wdl > 0) then wdl = wdl:lower() wdl = in_array (wdl, {"false", "no", "0"}) else -- wdl is empty, so wdl = false end local props = nil local fallback = nil if mw.wikibase.entityExists(qid) then props = mw.wikibase.getAllStatements(qid, propertyID) if props and fallbackID then fallback = mw.wikibase.getAllStatements(qid, fallbackID) end end -- Make sure it actually has at least one of the properties requested if not (props and props[1]) and not (fallback and fallback[1]) then return nil end -- So now we have something to return: -- table 'out' is going to store the names(s): -- and table 'link' will store any links to the name's article local out = {} local link = {} local maxpos = 0 if props and props[1] then for k, v in pairs(props) do maxpos = makelink(v, out, link, maxpos, wdl) end end if fallback and fallback[1] then -- second properties for k, v in pairs(fallback) do maxpos = makelink(v, out, link, maxpos, wdl) end end -- if there's anything to return, then insert the additions in the template arguments table -- in the form |author1=firstname secondname |author2= ... -- Renumber, in case we have inconsistent numbering local keys = {} for k, v in pairs(out) do keys[#keys + 1] = k end table.sort(keys) -- as they might be out of order for i, k in ipairs(keys) do out[k] = out[k]:gsub ('&#39;', '\''); -- prevent cs1|2 multiple names categorization; replace html entity with the actual character mw.log(i .. " " .. k .. " " .. (out[k])) if args[nl_type .. i] then -- name gets overwritten -- pull corresponding -link only if overwritten name is same as WD name if link[k] and (args[nl_type .. i] == out[k]) then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end else -- name does not get overwritten, so pull name from WD args[nl_type .. i] = out[k] if link[k] then args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn end end end end -- gets language codes used for a monolingual text property as a table function p._getLangOfProp(qid, pid) if not pid then return {} end local out = {} local props = mw.wikibase.getAllStatements(qid, pid) for i, v in ipairs(props) do if v.mainsnak.datatype == "monolingualtext" and v.mainsnak.datavalue then out[#out + 1] = v.mainsnak.datavalue.value.language end end return out end function p.getLangOfProp(frame) local pid = frame.args.pid or mw.text.trim(frame.args[1] or "") if pid == "" then return end local qid = frame.args.qid if qid == "" then qid = nil end return table.concat(p._getLangOfProp(qid, pid), ", ") end -- gets the language codes of a Wikidata entry as a table local function _lang_code(qid) local lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P424", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P218", ps = 1} ) if lc then return mw.text.split( lc, "[, ]+" ) end return p._getLangOfProp(qid, "P1476") end function p.lang_code(frame) return table.concat(_lang_code(frame.args.qid or mw.text.trim(frame.args[1] or "")), ", ") end -- export for debug function p.getPropOfProp(frame) return getPropOfProp(frame.args) end -- wraps a string in nowiki unless disable flag is set local function wrap_nowiki(str, disable) if disable then return str or '' end return mw.text.nowiki(str or '') end -- sort sequence table whose values are key-value pairs by key local function comp_key(a, b) return a[1] < b[1] end -- sort sequence table whose values are key-value pairs by value local function comp_val(a, b) return a[2] < b[2] end --[[-------------------------< C I T E _ Q >------------------------------------------------------------------ Takes standard CS1|2 template parameters and passes all to {{citation}}. If neither of |author= and |author1= are set, calls get_authors() to try to get an author name-list from Wikidata. The result is passed to {{citation}} for rendering. --]] function p._cite_q (citeq_args) local frame = mw.getCurrentFrame() -- parameters that don't get passed to Citation local expand = citeq_args.expand -- when set to anything, causes {{cite q}} to render <code><nowiki>{{citation|...}}</nowiki></code> local qid = citeq_args.qid or citeq_args[1] local wdl = citeq_args.wdl local template = citeq_args.template citeq_args.expand = nil citeq_args[1] = nil citeq_args.qid = nil citeq_args.wdl = nil citeq_args.template = nil -- if title supplied, flag to not read html title local titleforced = (citeq_args.title ~= nil) local oth = {} -- put the language codes into a sequential table langcodes[] local langcodes = {} if citeq_args.language then -- check these are a supported language codes for lc in mw.text.gsplit( citeq_args.language, "[, ]+", false ) do langcodes[#langcodes+1] = mw.language.isSupportedLanguage(citeq_args.language) and citeq_args.language end end if not langcodes[1] then -- try to find language of work langcodes = _lang_code(qid) end if not langcodes[1] then -- try fallback to journal's language local journal_qid = followQid({qid = qid, props = "P1433"}) langcodes = journal_qid and _lang_code(journal_qid) end citeq_args.language = citeq_args.language or table.concat(langcodes, ", ") -- loop through list of simple properties and get their values in citeq_args for name, data in pairs(simple_properties) do citeq_args[name] = getValue( {data.id, fwd = "ALL", osd = "no", noicon = "true", qid = qid, maxvals = data.maxvals, linked = data.linked, rank = data.rank or "best", citeq_args[name] } ) if data.populate_from_journal then local publishedin = getValue( {"P1433", ps = 1, qid = qid, maxvals = 0, citeq_args[name], qual = data.id, qualsonly = 'yes'} ) citeq_args[name] = publishedin or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals = data.maxvals, ps = 1}) end if citeq_args[name] and citeq_args[name]:find('[[Category:缺少維基數據信息的條目]]', 1, true) then -- try fallback to work's native language citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = langcodes[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned -- try fallback to qid's native language local qid_languages = _lang_code(citeq_args[name]) citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = qid_languages[1] } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned again citeq_args[name] = nil else -- record the language found if no lang specified citeq_args.language = citeq_args.language or qid_languages[1] end end end if data.others then oth[#oth + 1] = citeq_args[name] and (name:gsub("^%l", string.upper) .. ": " .. citeq_args[name]) citeq_args[name] = nil end end citeq_args.others = citeq_args.others or table.concat(oth, ". ") if citeq_args.others == "" then citeq_args.others = nil end citeq_args.journal = citeq_args.journal and citeq_args.journal:gsub("^''", ""):gsub("''$", ""):gsub("|''", "|"):gsub("'']]", "]]") citeq_args.ol = (getValue( {"P648", ps = 1, qid = qid, maxvals = 1, citeq_args.ol } ) or ''):gsub("^OL(.+)$", "%1") if citeq_args.ol == "" then citeq_args.ol = nil end -- TBD. Take care of |ol-access=? citeq_args.biorxiv = citeq_args.biorxiv and ("10.1101/" .. citeq_args.biorxiv) citeq_args.isbn = getValue( {"P957", ps = 1, qid = qid, maxvals = 1, rank="best", citeq_args.isbn } ) -- try ISBN 10 (only one value accepted) if citeq_args["publication-date"] then citeq_args["publication-date"] = mw.getCurrentFrame():expandTemplate { title = "ISOdate", args = {citeq_args["publication-date"]} } end -- if url then see if there's an archive: citeq_args.url local url if not citeq_args.url then for i, pr in ipairs( {"P953", "P856", "P2699"} ) do url = getValue( {pr, ps = 1, qid = qid, maxvals = 1, qual="P1065" } ) if url then citeq_args.url = mw.text.split( url, " (", true )[1] local arcurl = mw.ustring.match( url, " %((.*)%)" ) -- when there is an archive url, <url> holds: url<space>(archive url); here extract the archive url if present if arcurl then local arcy, arcm, arcd = arcurl:match("(20%d%d)%p?(%d%d)%p?(%d%d)") if arcy and arcm and arcd then citeq_args["archive-url"] = arcurl citeq_args["archive-date"] = tonumber(arcd) .. " " .. i18n.months[tonumber(arcm)] .. " " .. arcy end end break end end end if citeq_args.publisher == "Unknown" then -- look for "stated as" (P1932) local stated_as = getValue( {"P123", ps = 1, qid = qid, maxvals = 1, qual="P1932", qo="y"} ) if stated_as then citeq_args.publisher = stated_as end end if not titleforced then -- Handle subtitle. if citeq_args.title then local subtitle = mw.wikibase.getBestStatements (qid, 'P1680'); if 0 ~= #subtitle then subtitle = subtitle[1].mainsnak.datavalue.value.text; citeq_args.title = citeq_args.title .. ": " .. subtitle end end local htmltitle = getValue( {"P1476", qual = "P6833", ps = 1, qid = qid, maxvals = 1, qo = "y"} ) if htmltitle then citeq_args.title = htmltitle:gsub("</?i>", "''") else local title_display = citeq_args.title or mw.wikibase.getLabel(qid) or (langcodes[1] and mw.wikibase.getLabelByLang(qid, langcodes[1])) or ("No label or title -- debug: " .. qid) if citeq_args.url then citeq_args.title = wrap_nowiki(title_display) else local slink = mw.wikibase.getSitelink(qid, "zhwiki") local slink_flag = false local wrap_title = '' local wslink = false if not slink then -- See if we have wikisource if not citeq_args.url then local wikisource_sitelink = mw.wikibase.getSitelink(qid, "zhwikisource") or nil if wikisource_sitelink then slink = ':s:'..wikisource_sitelink wslink = true end end end if citeq_args.title then if slink then wrap_title = wrap_nowiki(citeq_args.title) slink_flag = true else citeq_args.title = wrap_nowiki(citeq_args.title) end else if slink and not wslink then if slink:lower() == title_display:lower() then citeq_args.title = '[[' .. slink .. ']]' else wrap_title = wrap_nowiki(slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")) slink_flag = true end elseif wslink then wrap_title = wrap_nowiki(title_display) slink_flag = true else citeq_args.title = wrap_nowiki(title_display) end end if slink_flag then if slink == wrap_title and not wslink then -- direct link citeq_args.title = '[[' .. slink .. ']]' else -- piped link citeq_args.title = '[[' .. slink .. '|' .. wrap_title .. ']]' end end end end end -- TBD: incorporate |at, |sheets= and |sheet= here as well -- Sort out what should happen if several of them are given at the same time if citeq_args.page or citeq_args.p then -- let single take precedence over multiple citeq_args.pages = nil citeq_args.pp = nil end if citeq_args.pages then local _, count = string.gsub(citeq_args.pages, "[,;%s]%d+", "") if count == 1 then citeq_args.page = citeq_args.pages citeq_args.pages = nil end end if is_set (qid) then if not is_set (citeq_args.author) and not is_set (citeq_args.author1) and not is_set (citeq_args.subject) and not is_set (citeq_args.subject1) and not is_set (citeq_args.host) and not is_set (citeq_args.host1) and not is_set (citeq_args.last) and not is_set (citeq_args.last1) and not is_set (citeq_args.surname) and not is_set (citeq_args.surname1) and not is_set (citeq_args['author-last']) and not is_set (citeq_args['author-last1']) and not is_set (citeq_args['author1-last']) and not is_set (citeq_args['author-surname']) and not is_set (citeq_args['author-surname1']) and not is_set (citeq_args['author1-surname1']) then -- if neither are set, try to get authors from Wikidata get_name_list ('author', citeq_args, qid, wdl) -- modify citeq_args table with authors from Wikidata end if not is_set (citeq_args.editor) and not is_set (citeq_args.editor1) and not is_set (citeq_args['editor-last']) and not is_set (citeq_args['editor-last1']) and not is_set (citeq_args['editor1-last']) and not is_set (citeq_args['editor-surname']) and not is_set (citeq_args['editor-surname1']) and not is_set (citeq_args['editor1-surname']) then -- if neither are set, try to get editors from Wikidata get_name_list ('editor', citeq_args, qid, wdl) -- modify citeq_args table with editors from Wikidata end if not is_set (citeq_args.translator) and not is_set (citeq_args.translator1) and not is_set (citeq_args['translator-last']) and not is_set (citeq_args['translator-last1']) and not is_set (citeq_args['translator1-last']) and not is_set (citeq_args['translator-surname']) and not is_set (citeq_args['translator-surname1']) and not is_set (citeq_args['translator1-surname']) then -- if neither are set, try to get translators from Wikidata get_name_list ('translator', citeq_args, qid, wdl) -- modify citeq_args table with translators from Wikidata end end for k, v in pairs(citeq_args) do if in_array (v, {'(())', 'unset', 'ignore'}) or 'string' ~= type(k) then -- empty accept-as-is-written (()) markup to indicate an empty/unused parameter value, other ((...)) markups are deliberately passed down to {{citation}} citeq_args[k] = nil elseif in_array (v, {'((unset))', '((ignore))'}) then -- strip off markup for free-text values clashing with local keywords citeq_args[k] = 'unset' end end local author_count = 0 for k, v in pairs(citeq_args) do if k:find("^author%d+$") then author_count = author_count + 1 end end if author_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-authors'] then citeq_args['display-authors'] = nil; -- unset because no longer needed else citeq_args['display-authors'] = citeq_args['display-authors'] or 3 -- limit to three displayed names end end local editor_count = 0 for k, v in pairs(citeq_args) do if k:find("^editor%d+$") then editor_count = editor_count + 1 end end if editor_count > 8 then -- convention in astronomy journals, optional mode for this? if 'all' == citeq_args['display-editors'] then citeq_args['display-editors'] = nil; -- unset because no longer needed else citeq_args['display-editors'] = citeq_args['display-editors'] or 3 -- limit to three displayed names end end -- change edition to ordinal if it's set and numeric citeq_args.edition = citeq_args.edition and p.makeOrdinal(citeq_args.edition) -- code to make a guess what template to use from the supplied parameters -- (first draft for proof-of-concept) if citeq_args.isbn then template = template or "book" citeq_args.asin = nil -- suppress ASIN if ISBN exists elseif citeq_args.journal then template = template or "journal" elseif citeq_args.website then template = template or "web" end -- template is CS1 designator: journal, web, news, etc. if template then -- citeq_args.mode = citeq_args.mode or "cs1" -- a cs1 template already knows that it is cs1 so this line is superfluous template = "Cite " .. template else -- citeq_args.mode = citeq_args.mode or "cs2" -- a cs2 template already knows that it is cs2 so this line is superfluous template = "Citation" end -- |id= could hold more than one identifier pulled from Wikidata not supported by {{citation}}, right now only add our qid to the list local list_sep = '. ' if citeq_args.mode ~= 'cs1' then list_sep = ', ' end local id = '[[WDQ (标识符)|Veizgiek Soqgawq]]&nbsp;[[:d:' .. qid .. '|' .. qid .. ']]' -- go through "WDQ (标识符)" redirect to reduce clutter in "链入页面" and improve reverse lookup. Keep in sync with {{QID}}. local old_id = citeq_args.id if wdl then -- show WD logo id = id .. '[[File:Wikidata-logo.svg|16px|alt=|link=]]' -- possibly replace by WD edit icon? end if is_set (old_id) then citeq_args.id = old_id .. list_sep .. id -- append to user-specified contents else citeq_args.id = id end -- clean up any blank parameters for k, v in pairs(citeq_args) do if v == "" then citeq_args[k] = nil end end -- if |expand=<anything>, write a nowiki'd version to see what the {{citation}} template call looks like if expand then local expand_args = { "{{" .. template } -- init with citation template if expand == "self" then citeq_args.id = old_id -- restore original |id= parameter expand_args = { "{{cite Q|" .. qid } -- expand to itself end -- make a sortable table and sort it by param name local sorttable = {} for param, val in pairs (citeq_args) do table.insert(sorttable, {param, val}) end table.sort(sorttable, comp_key) -- add contents to expand_args for idx, val in ipairs(sorttable) do table.insert(expand_args, val[1] .. '=' .. val[2]) end -- make the nowiki'd string and done return "<code>" .. table.concat (expand_args, ' |') .. "}}</code>" end local erratumid = getPropertyIDs( { "P2507", qid = qid, fwd = "ALL", osd = "no", rank = "best", maxvals = 1 } ) if erratumid then erratumid = " [[d:" .. erratumid .. "|(erratum)]]" .. "[[Category:Cite Q - 引用含勘误表的作品]]" else erratumid = "" end local opt_cat = '' if getValue( {"P5824", ps = 1, qid = qid} ) then opt_cat = '[[Category:Cite Q - 引用被撤稿的作品]]<!-- retracted -->' end if getValue( {"P1366", ps = 1, qid = qid} ) then opt_cat = opt_cat .. '[[Category:Cite Q - 引用被替换的作品]]<!-- replaced -->' end return frame:expandTemplate{title = template, args = citeq_args} .. erratumid .. opt_cat -- render the template end function p.cite_q (frame) local args = {} for k, v in pairs(frame:getParent().args) do if v ~= "" then args[k] = v end end -- From #invoke -- -- {{#property: will return values separated by MediaWiki:Comma-separator, -- which have a zero-width space to allow line wrap. -- However, Module:Citation/CS1/Configuration blacklisted invisible_chars, -- which include the zero-width space. -- To fix the unexpected warning message, simply replace them here should be -- the simplest way without breaking Special:ActiveLanguages on translatewiki -- and various places. -- Also, we need ", " instead of "、" for citations. for k, v in pairs(frame.args) do if v ~= "" then args[k] = string.gsub(v, "、​", ", " ) end end args.qid = args.qid or args[1] or "" if args.qid == "" then return nil end args[1] = nil local citesep = (args.citesep or "") if citesep == "" then citesep = ", " end citesep = citesep:gsub('"', '') -- strip double quotes after setting default to allow |citesep="" as a blank separator args.citesep = nil local tag = args.tag or "" if tag == "" then tag = nil end args.tag = nil local list = args.list or "" if list == "" then list = nil end args.list = nil args.language = args.language or args.lang args.lang = nil local cites = {} for q in args.qid:gmatch("Q%d+") do -- make a new copy of the arguments local newargs = {} for k, v in pairs(args) do if k ~= "qid" then newargs[k] = v end end newargs.qid = q if tag == "ref" then cites[#cites + 1] = frame:callParserFunction{ name = "#tag:ref", args = { p._cite_q(newargs), name = q } } -- expand like this: args = { p._cite_q(newargs), name = 'foo', group = 'bar' } else cites[#cites + 1] = p._cite_q(newargs) end end if list then return frame:expandTemplate{ title = list, args = cites } else return table.concat(cites, citesep) end end return p g8bih7m8hryi6rg9gfx777lna422jf6 模块:Complex date 828 14847 43053 2026-07-07T17:55:02Z 内存溢出的猫 7954 From [[zh:Module:Complex date]] 43053 Scribunto text/plain --[[ __ __ _ _ ____ _ _ | \/ | ___ __| |_ _| | ___ _ / ___|___ _ __ ___ _ __ | | _____ __ __| | __ _| |_ ___ | |\/| |/ _ \ / _` | | | | |/ _ (_) | / _ \| '_ ` _ \| '_ \| |/ _ \ \/ / / _` |/ _` | __/ _ \ | | | | (_) | (_| | |_| | | __/_| |__| (_) | | | | | | |_) | | __/> < | (_| | (_| | || __/ |_| |_|\___/ \__,_|\__,_|_|\___(_)\____\___/|_| |_| |_| .__/|_|\___/_/\_\ \__,_|\__,_|\__\___| |_| This module is intended for creation of complex date phrases in variety of languages. Once deployed, please do not modify this code without applying the changes first at Module:Complex date/sandbox and testing at Module:Complex date/sandbox/testcases. Authors and maintainers: * User:Sn1per - first draft of the original version * User:Jarekt - corrections and expansion of the original version ]] -- List of external modules and functions local p = {Error = nil} local i18n = require('Module:i18n/complex date') -- used for translations of date related phrases local ISOdate = require('Module:ISOdate')._ISOdate -- used for parsing dates in YYYY-MM-DD and related formats local Calendar -- loaded lazily -- ================================================== -- === Internal functions =========================== -- ================================================== local function langSwitch(list,lang) local langList = mw.language.getFallbacksFor(lang) table.insert(langList,1,lang) table.insert(langList,math.max(#langList,2),'default') for i,language in ipairs(langList) do if list[language] then return list[language] end end end -- ================================================== local function formatnum1(numStr, lang) -- mostly require('Module:Formatnum').formatNum function used to translate a number to use different numeral characters, -- except that it it does not call that function unless the language is on the list "LList" local LList = {bn=1,bpy=1,kn=1,hi=1,mr=1,new=1,pa=1,gu=1,fa=1,glk=1,mzn=1,ur=1,ar=1,ckb=1,ks=1,lo=1,['or']=1,bo=1,['ml-old']=1,mn=1,te=1,th=1} if LList[lang] then -- call only when the language is on the list numStr = require('Module:Formatnum').formatNum(numStr, lang, 1) end return numStr end -- ================================================== local function getISODate(datestr, datetype, lang, num, case) -- translate dates in the format YYYY, YYYY-MM, and YYYY-MM-DD if not case and i18n.Translations[datetype] then -- look up the grammatical case needed and call ISOdate module local rec = langSwitch(i18n.Translations[datetype], lang) if type(rec)=='table' then case = rec.case[num] end end return ISOdate(datestr, lang, case, '', 1) end -- ======================================================================= local function translatePhrase(date1, date2, operation, lang, state) -- use tables in Module:i18n/complex date to translate a phrase if not i18n.Translations[operation] then p.Error = string.format('<span style="background-color:red;">Error in [[Module:Complex date]]: input parameter "%s" is not recognized.</span>', operation or 'nil') return '' end local dateStr = langSwitch(i18n.Translations[operation], lang) if type(dateStr)=='table' then dateStr = dateStr[1] end if type(dateStr)=='function' then local dateFunc = dateStr local nDates = i18n.Translations[operation]['nDates'] if nDates==2 then -- 2 date phrase dateStr = dateFunc(date1, date2, state) else -- 1 date phrase dateStr = dateFunc(date1, state) end end if type(dateStr)=='string' then -- replace parts of the string '$date1' and '$date2' with date1 and date2 strings dateStr = mw.ustring.gsub(dateStr, '$date1', date1) dateStr = mw.ustring.gsub(dateStr, '$date2', date2) else -- Special case of more complex phrases that can be build out of simple phrases -- If complex case is not translated to "lang" than build it out of simpler ones local x = dateStr dateStr = p._complex_date(x.conj, x.adj1, date1, x.units1, x.era1, x.adj2, date2, x.units2, x.era2, lang, 2) end return dateStr end -- ======================================================================= local function oneDatePhrase(dateStr, adj, era, units, lang, num, case, state) -- translate a single date phrase if num==2 then state.adj, state.era, state.units, state.precision = state.adj2, state.era2, state.units2, state.precision2 end -- dateStr can have many forms: ISO date, year or a number for -- decade, century or millennium if units == '' then -- unit is "year", "month", "day" dateStr = getISODate(dateStr, adj, lang, num, case) else -- units is "decade", "century", "millennium'' dateStr = translatePhrase(dateStr, '', units, lang, state) end -- add adjective ("early", "mid", etc.) or preposition ("before", "after", -- "circa", etc.) to the date if adj ~= '' then dateStr = translatePhrase(dateStr, '', adj, lang, state) else -- only era? dateStr = formatnum1(dateStr, lang) end -- add era if era ~= '' then dateStr = translatePhrase(dateStr, '', era, lang, state) end return dateStr end -- ======================================================================= local function twoDatePhrase(date1, date2, state, lang) -- translate a double date phrase local dateStr, case local era='' if state.era1 == state.era2 then -- if both eras are the same than add it only once era = state.era1 state.era1 = '' state.era2 = '' end case = {nil, nil} if i18n.Translations[state.conj] then local rec = langSwitch(i18n.Translations[state.conj], lang) if type(rec)=='table' then case = rec.case end end date1 = oneDatePhrase(date1, state.adj1, state.era1, state.units1, lang, 1, case[1], state) date2 = oneDatePhrase(date2, state.adj2, state.era2, state.units2, lang, 2, case[2], state) dateStr = translatePhrase(date1, date2, state.conj, lang, state) if era ~= '' then dateStr = translatePhrase(dateStr, '', era, lang, state) end return dateStr end -- ======================================================================= local function otherPhrases(date1, date2, operation, era, lang, state) -- translate specialized phrases local dateStr = '' if operation == 'islamic' then if date2=='' then date2 = mw.getCurrentFrame():callParserFunction('#time', 'xmY', date1) end date1 = getISODate(date1, operation, lang, 1, nil) date2 = getISODate(date2, operation, lang, 2, nil) if era == '' then era = 'ad' end dateStr = translatePhrase(date1, '', era, lang, state) .. ' (' .. translatePhrase(date2, '', 'ah', lang, state) .. ')' era = '' elseif operation == 'julian' then if not date2 and date1 then -- Convert from Julian to Gregorian calendar date if Calendar == nil then Calendar = require("Module:Calendar") -- lazy loding (only if needed) end local JDN = Calendar._date2jdn(date1, 0) if JDN then date2 = date1 -- first date is assumed to be Julian date1 = Calendar._jdn2date(JDN, 1) end end date1 = getISODate(date1, operation, lang, 1, nil) date2 = getISODate(date2, operation, lang, 2, nil) dateStr = translatePhrase(date1, date2, operation, lang, state) dateStr = mw.ustring.gsub(mw.ustring.gsub(dateStr, '%( ', '('), ' %)', ')') -- in case date2 is empty elseif operation == 'turn of the year' or operation == 'turn of the decade' or operation == 'turn of the century' then local dt = 1 if operation == 'turn of the decade' then dt=10 end if not date2 or date2=='' then date2=tostring(tonumber(date1)-dt) end if era~='bp' and era~='bc' then date1, date2 = date2, date1 end if operation == 'turn of the year' then date1 = ISOdate(date1, lang, '', '', 1) date2 = ISOdate(date2, lang, '', '', 1) else date1 = formatnum1(date1, lang) date2 = formatnum1(date2, lang) end dateStr = translatePhrase(date1, date2, operation, lang, state) elseif operation == 'year unknown' then dateStr = translatePhrase('', '', operation, lang, state) .. '<div style="display: none;">Unknown date</div>' elseif operation == 'unknown' then dateStr = tostring(mw.message.new( "exif-unknowndate" ):inLanguage( lang )) .. '<div style="display: none;">Unknown date</div>' end -- add era if era ~= '' then dateStr = translatePhrase(dateStr, '', era, lang, state) end return dateStr end -- ======================================================================= local function checkAliases(str1, str2, sType) -- some inputs have many aliases - reconcile them and ensure string is playing a proper role local out = '' if str1 and str1~='' then local a = i18n.Synonyms[str1] -- look up synonyms of "str1" if a then out = a[1] else p.Error = string.format('<span style="background-color:red;">Error in [[Module:Complex date]]: %s is not recognized.</span>', str1) end elseif str2 and str2~='' then -- if "str1" of type "sType" is empty than maybe ... local a = i18n.Synonyms[str2] -- ..."str2" is of the same type and is not empty if a and a[2]==sType then out = a[1] str2 = '' end end return out, str2 end -- ======================================================================= local function datePrecision(dateStr, units) -- "in this module "Units" is a string like millennium, century, or decade -- "precision" is wikibase compatible date precision number: 6=millennium, 7=century, 8=decade, 9=year, 10=month, 11=day -- based on string or numeric input calculate "Units" and "precision" local precision if type(units)=='number' then precision = units if precision>11 then precision=11 end -- clip the range of precision values if precision==6 then units='millennium' elseif precision==7 then units='century' elseif precision==8 then units='decade' else units = '' end elseif type(units)=='string' then units = string.lower(units) if units=='millennium' then precision=6 elseif units=='century' then precision=7 elseif units=='decade' then precision=8 else precision=9 end end if units=='' or precision==9 then local sLen = mw.ustring.len(dateStr) if sLen<= 4 then precision=9 elseif sLen== 7 then precision=10 elseif sLen>=10 then precision=11 end units='' end if precision==6 and dateStr.match( dateStr, '%d000' )~=nil then dateStr = tostring(math.floor(tonumber(dateStr)/1000) +1) elseif precision==7 and mw.ustring.match( dateStr, '%d%d00' )~=nil then dateStr = tostring(math.floor(tonumber(dateStr)/100) +1) end return dateStr, units, precision end -- ======================================================================= local function isodate2timestamp(dateStr, precision, era) -- convert date string to timestamps used by Quick Statements local tStamp = nil if era == 'ah' or precision<6 then return nil elseif era ~= '' then local eraLUT = {ad='+', bc='-', bp='-' } era = eraLUT[era] else era='+' end -- convert isodate to timestamp used by quick statements if precision>=9 then if string.match(dateStr,"^%d%d%d%d$") then -- if YYYY format tStamp = era .. dateStr .. '-00-00T00:00:00Z/9' elseif string.match(dateStr,"^%d%d%d%d%-%d%d$") then -- if YYYY-MM format tStamp = era .. dateStr .. '-00T00:00:00Z/10' elseif string.match(dateStr,"^%d%d%d%d%-%d%d%-%d%d$") then -- if YYYY-MM-DD format tStamp = era .. dateStr .. 'T00:00:00Z/11' end elseif precision==8 then -- decade tStamp = era .. dateStr .. '-00-00T00:00:00Z/8' elseif precision==7 then -- century local d = tostring(tonumber(dateStr)-1) tStamp = era .. d .. '50-00-00T00:00:00Z/7' elseif precision==6 then local d = tostring(tonumber(dateStr)-1) tStamp = era .. d .. '500-00-00T00:00:00Z/6' end return tStamp end -- ======================================================================= local function oneDateQScode(dateStr, adj, era, precision) -- create QuickStatements string for "one date" dates local outputStr = '' local d = isodate2timestamp(dateStr, precision, era) if not d then return '' end local rLUT = { early='Q40719727' , mid='Q40719748', late='Q40719766', ['1quarter']='Q40690303' , ['2quarter']='Q40719649' , ['3quarter']='Q40719662', ['4quarter']='Q40719674', spring='Q40720559' , summer='Q40720564' , autumn='Q40720568' , winter='Q40720553', firsthalf='Q40719687', secondhalf='Q40719707' } local qLUT = {['from']='P580', ['until']='P582', ['after']='P1319', ['before']='P1326', ['by']='P1326'} local refine = rLUT[adj] local qualitier = qLUT[adj] if adj=='' then outputStr = d elseif adj=='circa' then outputStr = d..",P1480,Q5727902" elseif refine then outputStr = d..",P4241,"..refine elseif precision>7 and qualitier then local century = string.gsub(d, 'Z%/%d+', 'Z/7') outputStr = century ..",".. qualitier ..","..d end return outputStr end -- ======================================================================= local function twoDateQScode(date1, date2, state) -- create QuickStatements string for "two date" dates if state.adj1~='' or state.adj2~='' or state.era1~=state.era2 then return '' -- QuickStatements string are not generated for two date phrases with adjectives end local outputStr = '' local d1 = isodate2timestamp(date1, state.precision1, state.era1) local d2 = isodate2timestamp(date2, state.precision2, state.era2) if (not d1) or (not d2) then return '' end -- find date with lower precision in common to both dates local cd local year1 = tonumber(string.sub(d1,2,5)) local year2 = tonumber(string.sub(d2,2,5)) local k = 0 for i = 1,10,1 do if string.sub(d1,1,i)==string.sub(d2,1,i) then k = i -- find last matching letter end end if k>=9 then -- same month, since "+YYYY-MM-" is in common cd = isodate2timestamp(string.sub(d1,2,8), 10, state.era1) elseif k>=6 and k<9 then -- same year, since "+YYYY-" is in common cd = isodate2timestamp(tostring(year1), 9, state.era1) elseif k==4 then -- same decade(k=4, precision=8), since "+YYY" is in common cd = isodate2timestamp(tostring(year1), 8, state.era1) elseif k==3 then -- same century(k=3, precision=7) since "+YY" is in common local d = tostring(math.floor(year1/100) +1) -- convert 1999 -> 20 cd = isodate2timestamp( d, 7, state.era1) elseif k==2 then -- same millennium (k=2, precision=6), since "+Y" is in common local d = tostring(math.floor(year1/1000) +1) -- convert 1999 -> 2 cd = isodate2timestamp( d, 6, state.era1) end if not cd then return '' end --if not cd then -- return ' <br/>error: ' .. d1.." / " .. d2.." / ".. (cd or '') .." / ".. string.sub(d1,2,5).." / " .. string.sub(d2,2,5).." / " .. tostring(k) --end -- if (state.conj=='from-until') or (state.conj=='and' and year1==year2-1) then outputStr = cd ..",P580,".. d1 ..",P582,".. d2 elseif (state.conj=='between') or (state.conj=='or' and year1==year2-1) then outputStr = cd ..",P1319,".. d1 ..",P1326,".. d2 elseif state.conj=='circa2' then outputStr = cd ..",P1319,".. d1 ..",P1326,".. d2 ..",P1480,Q5727902" end return outputStr end -- ======================================================================= local function processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) -- process inputs and save date in state array local state = {} state.conj = string.lower(conj or '') state.adj1 = string.lower(adj1 or '') state.adj2 = string.lower(adj2 or '') state.era1 = string.lower(era1 or '') state.era2 = string.lower(era2 or '') state.units1 = string.lower(units1 or '') state.units2 = string.lower(units2 or '') -- if date 1 is missing but date 2 is provided than swap them if date1 == '' and date2 ~= '' then date1 = date2 date2 = '' state = {adj1 = state.adj2, era1 = state.era2, units1 = state.units2, adj2 = '', era2 = '', units2 = '', conj=state.conj, num=1} end if date2 ~= '' then state.nDates = 2 elseif date1 ~= '' then state.nDates = 1 else state.nDates = 0 end -- reconcile alternative names for text inputs local conj = checkAliases(state.conj ,'' ,'j') state.adj1 ,conj = checkAliases(state.adj1 ,conj,'a') state.units1,conj = checkAliases(state.units1,conj,'p') state.era1 ,conj = checkAliases(state.era1 ,conj,'e') state.special,conj = checkAliases('',conj,'c') state.adj2 = checkAliases(state.adj2 ,'','a') state.units2 = checkAliases(state.units2,'','p') state.era2 = checkAliases(state.era2 ,'','e') state.conj = conj state.lang = lang if p.Error~=nil then return nil end -- calculate date precision value date1, state.units1, state.precision1 = datePrecision(date1, state.units1) date2, state.units2, state.precision2 = datePrecision(date2, state.units2) -- Handle special cases -- Some complex phrases can be created out of simpler ones. Therefore on pass # 1 we try to create -- the phrase using complex phrase and if that is not found than on the second pass we try to build -- the phrase out of the simpler ones if passNr==1 then if state.adj1=='circa' and state.nDates == 2 then state.conj = 'circa2' state.adj1 = '' state.adj2 = '' end if state.nDates == 2 and state.adj1=='late' and state.adj2=='early' and state.conj=='and' and state.units1==state.units2 and state.era1==state.era2 then if state.units1=='century' then state.conj='turn of the century' elseif state.units1=='decade' then state.conj='turn of the decade' elseif state.units1=='' then state.conj='turn of the year' end state.adj1 = '' state.adj2 = '' state.units1 = '' state.units2 = '' end end state.adj, state.era, state.units, state.precision = state.adj1, state.era1, state.units1, state.precision1 return date1, date2, state end -- ================================================== -- === External functions =========================== -- ================================================== function p.Era(frame) -- process inputs local dateStr local args = frame.args if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language end local lang = args['lang'] local dateStr = args['date'] or '' local eraType = string.lower(args['era'] or '') dateStr = ISOdate(dateStr, lang, '', '', 1) if eraType then eraType = checkAliases(eraType ,'','e') dateStr = translatePhrase(dateStr, '', eraType, lang, {}) end return dateStr end -- ======================================================================= function p._complex_date(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) local Output='' local state -- process inputs and save date in state array date1, date2, state = processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, passNr) if p.Error~=nil then return nil end local errorStr = string.format( '\n*conj=%s, adj1=%s, era1=%s, unit1=%s, prec1=%i, adj2=%s, era2=%s, unit2=%s, prec2=%i, special=%s', state.conj, state.adj1, state.era1, state.units1, state.precision1, state.adj2, state.era2, state.units2, state.precision2, state.special) -- call specialized functions local QScode = '' if state.special~='' then Output = otherPhrases(date1, date2, state.special, state.era1, lang, state) elseif state.conj~='' then QScode = twoDateQScode(date1, date2, state) Output = twoDatePhrase(date1, date2, state, lang) elseif state.adj1~='' or state.era1~='' or state.units1~='' then Output = oneDatePhrase(date1, state.adj1, state.era1, state.units1, lang, 1, nil, state) QScode = oneDateQScode(date1, state.adj1, state.era1, state.precision1) elseif date1~='' then Output = ISOdate(date1, lang, '', 'dtstart', '100-999') end if p.Error~=nil then return errorStr end -- if there is any wikicode in the string than execute it if mw.ustring.find(Output, '{') then Output = mw.getCurrentFrame():preprocess(Output) end if QScode and #QScode>0 then QScode = ' <div style="display: none;">date QS:P,' .. QScode .. '</div>' end return Output .. QScode end -- ======================================================================= function p._complex_date_cer(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, certainty, lang) -- same as p._complex_date but with extra parameter for certainty: probably, possibly, presumably, etc. local dateStr = p._complex_date(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, 1) certainty = checkAliases(certainty, conj, 'r') local LUT = {probably='Q56644435', presumably='Q18122778', possibly='Q30230067', circa='Q5727902' } if certainty and LUT[certainty] then local state = {} date1, date2, state = processInputParams(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, lang, 1) dateStr = translatePhrase(dateStr, '', certainty, lang, state) dateStr = string.gsub(dateStr, '(%<div style="display: none;"%>date QS:P,[^%<]+)(%</div%>)', '%1,P1480,' .. LUT[certainty] .. '%2' ) end return dateStr end -- ======================================================================= function p.complex_date(frame) -- process inputs local dateStr local args = frame.args if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language end local date1 = args['date1'] or args['2'] or args['date'] or '' local date2 = args['date2'] or args['3'] or '' local conj = args['conj'] or args['1'] or '' local adj1 = args['adj1'] or args['adj'] or '' local adj2 = args['adj2'] or '' local units1 = args['precision1'] or args['precision'] or '' local units2 = args['precision2'] or args['precision'] or '' local era1 = args['era1'] or args['era'] or '' local era2 = args['era2'] or args['era'] or '' local certainty = args['certainty'] local lang = args['lang'] dateStr = p._complex_date_cer(conj, adj1, date1, units1, era1, adj2, date2, units2, era2, certainty, lang) if p.Error~=nil then dateStr = p.Error .. '[[Category:Pages using Complex date template with incorrect parameter]]' end return dateStr end return p ppv1t08ydt8a9x36u2iltdsomq7mcr5 模块:I18n/complex date 828 14848 43054 2026-07-07T17:55:10Z 内存溢出的猫 7954 From [[zh:Module:i18n/complex date]] 43054 Scribunto text/plain --[[ __ __ _ _ ___ _ ___ __ _ _ _ | \/ | ___ __| |_ _| | ___ _|_ _/ |( _ ) _ __ / /__ ___ _ __ ___ _ __ | | _____ __ __| | __ _| |_ ___ | |\/| |/ _ \ / _` | | | | |/ _ (_)| || |/ _ \| '_ \ / / __/ _ \| '_ ` _ \| '_ \| |/ _ \ \/ / / _` |/ _` | __/ _ \ | | | | (_) | (_| | |_| | | __/_ | || | (_) | | | |/ / (_| (_) | | | | | | |_) | | __/> < | (_| | (_| | || __/ |_| |_|\___/ \__,_|\__,_|_|\___(_)___|_|\___/|_| |_/_/ \___\___/|_| |_| |_| .__/|_|\___/_/\_\ \__,_|\__,_|\__\___| |_| This code was copied from Commons please request changes there. Maintainers: *Jarekt ]] local Ordinal = require('Module:Ordinal')._Ordinal local Roman = require('Module:Roman')._Numeral -- ========================================================================== -- === Local Helper functions ============================================== -- ========================================================================== -- form of French "of" based on "precision", which is wikibase compatible date precision format: -- 6=millennium, 7=century, 8=decade, 9=year, 10=month, 11=day -- 1 2 3 4 5 mill cent deca year month day local frOf = {'du','du','du','du','du', 'du', 'du', 'de', 'de', 'de', 'du'} local function decYear(state,lang,case) --Declension of word "year" in several languages if state.precision == 9 then yearCase = { fi={xxx='vuosien', gen='vuoden', ill='vuoteen', ptv='vuotta', ela='vuodesta', ine='vuonna'}, sl={insP='letoma', ins='letom', gen='leta', loc='letu'}, hsb={insP='lětami', ins='lětom', gen='lěta', loc='lěće'} } return yearCase[lang][case] .. ' ' else return '' end end local function decCentury(lang,case) --Declension of word "century" in several languages centuryCase = { pl={nom='wiek', gen='wieku', ins='wiekiem', loc='wieku', default = 'wiek'}, hsb={nom='lětstotk', gen='lětstotka', ins='lětstotkom', loc='lětstotku', default = 'lětstotk'} } return centuryCase[lang][case] or centuryCase[lang]['default'] end local function decMillennium(lang,case) --Declension of word "century" in several languages millenniumCase = { pl={nom='tysiąclecie', gen='tysiąclecia', ins='tysiącleciem', loc='tysiącleciu', default = 'tysiąclecie'}, hsb={nom='lěttysac', gen='lěttysaca', ins='lěttysacom', loc='lěttysacu', default = 'lěttysac'} } return millenniumCase[lang][case] or millenniumCase[lang]['default'] end -- ========================================================================== -- === Output data structure =============================================== -- ========================================================================== local p = {} --[[ Multiple formats are possible: 1) string with key words "$date1" and "$date2" which will be replaced later by the date strings 2) function which can be used to create output string * Function INPUTS: - date1 and date2 string with date strings. "$date1" and "$date2" can also be used which will be replaced latter - state is a table with full description of the phrase we are trying to construct. It includes state.precision1 (and 2) which is wikibase compatible date precision format: 6=millennium, 7=century, 8=decade, 9=year, 10=month, 11=day 3) table with following fields: * table[1] is either string or a function * table.case is a 2 element table with Grammatical cases used by given language to alter month name or other adjective related to date # 1 and 2 ]] p.Translations = { -- ========================================== -- === Two date phrases ===================== -- ========================================== ['from-until'] = { nDates = 2, ar='من $date1 إلى $date2', ['be-tarask']={'з $date1 да $date2', case={'gen','gen'}}, bn='$date1 থেকে $date2 পর্যন্ত', ca='$date1 fins $date2', cs='$date1 až $date2', da='fra $date1 til $date2', de='$date1 bis $date2', el='από $date1 έως $date2', en='from $date1 until $date2', ['en-gb']='from $date1 until $date2', ['en-ca']='from $date1 until $date2', eo='de $date1 al $date2', es='de $date1 a $date2', et='$date1 kuni $date2', fa='از $date1 تا $date2', fi='$date1–$date2', -- välisenä aikana fr=function(date1, date2, state) -- could actually be better should be "d'octobre à mars 2013' not "de octore 2013 à mars 2013" if state.precision > 10 then -- precision > month return 'du $date1 au $date2' else -- "DE septebmbre" / "D'octobre" return require("Module:Linguistic").of(date1, 'fr') .. " à $date2" end end, gl='de $date1 a $date2', --Template:From until used 'desde $date1 ata $date2' he='מ- $date1 עד $date2', hr='od $date1 do $date2', hsb={'wot $date1 do $date2', case={'gen','gen'}}, hu='$date1 – $date2', it='dal $date1 al $date2', ja='$date1から$date2まで', mk='од $date1 до $date2', ml='$date1 മുതൽ $date2 വരെ', nb='fra $date1 til $date2', nds='$date1 bet $date2', nn='fra $date1 til $date2', nl='$date1 tot $date2', no='fra $date1 til $date2', pl={'od $date1 do $date2', case={'gen','gen'}}, ro='din $date1 până în $date2', pt='de $date1 a $date2', qu="$date1 p'unchawmanta $date2 p\'unchawkama", ru={'с $date1 по $date2', case={'gen','gen'}}, sk={'od $date1 do $date2', case={'gen','gen'}}, sl={'od $date1 do $date2', case={'gen','gen'}}, sv='från $date1 till $date2', uk={'з $date1 до $date2', case={'gen','gen'}}, ur='از $date1 تا $date2', vi='từ $date1 đến $date2', ['zh-hans']='从$date1到$date2', ['zh-hant']='從$date1到$date2', default='<span style="color:red">$date1 - $date2</span>', }, ['between']={ nDates = 2, ar='بين $date1 و $date2', ['be-tarask']={'між $date1 і $date2', case={'ins','ins'}}, bn='$date1 এবং $date2-এর মাঝামাঝি', ca='entre $date1 i $date2', cs={'mezi $date1 a $date2', case={'ins','ins'}}, da='mellem $date1 og $date2', de='zwischen $date1 und $date2', el='μεταξύ $date1 και $date2', en='between $date1 and $date2', ['en-gb']='between $date1 and $date2', ['en-ca']='between $date1 and $date2', eo='inter $date1 kaj $date2', es='entre $date1 y $date2', et='$date1 ja $date2 vahel', fa='بین $date1 و $date2', fi={function(date1, date2, state) return decYear(state,'fi','xxx') .. '$date1 ja $date2 välisenä aikana' end, case={'gen','gen'}}, fr='entre $date1 et $date2', gl='entre $date1 e $date2', he='בין $date1 ו- $date2', hr='između $date1 i $date2', hsb={'mjez $date1 a $date2', case={'ins','ins'}}, hu='$date1 és $date2 között', hi='$date1 और $date2 के बीच', it='tra il $date1 e il $date2', ja='$date1と$date2の間', mk='помеѓу $date1 и $date2', ml='$date1, $date2 എന്നിവയ്ക്കിടയ്ക്ക്', nb='mellom $date1 og $date2', nds='twischen $date1 un $date2', nn='mellom $date1 og $date2', nl='tussen $date1 en $date2', no='mellom $date1 og $date2', pl={'między $date1 a $date2', case={'ins','ins'}}, ro='între $date1 și $date2', pt='entre $date1 e $date2', qu="$date1 p'unchawpa $date2 p'unchawpapas chawpin", ru={'между $date1 и $date2', case={'ins','ins'}}, sk={'medzi $date1 a $date2', case={'ins','ins'}}, sl={function(date1, date2, state) return 'med ' .. decYear(state,'sl','insP') .. '$date1 in $date2' end, case={'ins','ins'}}, sv='mellan $date1 och $date2', uk={'між $date1 та $date2', case={'ins','ins'}}, ur='بین $date1 و $date2', vec='tra el $date1 e el $date2', vi='giữa $date1 và $date2', ['zh-hans']='在$date1到$date2之间', ['zh-hant']='在$date1到$date2之間', default='<span style="color:red">$date1 - $date2</span>', }, ['or'] = { nDates = 2, ar='$date1 أو $date2', ['be-tarask']='$date1 ці $date2', bn='$date1 অথবা $date2', ca='$date1 o $date2', cs='$date1 nebo $date2', da='$date1 eller $date2', de='$date1 oder $date2', el='$date1 ή $date2', en='$date1 or $date2', ['en-gb']='$date1 or $date2', ['en-ca']='$date1 or $date2', eo='$date1 aŭ $date2', es='$date1 o $date2', et='$date1 või $date2', fa='$date1 یا $date2', fi='$date1 tai $date2', fr='$date1 ou $date2', gl='$date1 ou $date2', he='$date1 או $date2', hr='$date1 ili $date2', hsb='$date1 abo $date2', hu='$date1 vagy $date2', it='$date1 o $date2', ja='$date1または$date2', mk='$date1 или $date2', ml='$date1 അഥവാ $date2', nb='$date1 eller $date2', nn='$date1 eller $date2', nds='$date1 oder $date2', nl='$date1 of $date2', no='$date1 eller $date2', pl='$date1 lub $date2', pt='$date1 ou $date2', qu='$date1 icha $date2', ro='$date1 sau $date2', ru='$date1 или $date2', sk='$date1 alebo $date2', sl='$date1 ali $date2', sv='$date1 eller $date2', uk='$date1 або $date2', ur='$date1 یا $date2', th='$date1 หรือ $date2', vi='$date1 hoặc $date2', ['zh-hans']='$date1或$date2', ['zh-hant']='$date1或$date2', default=function(date1, date2, state) return require("Module:Linguistic").conj({date1, date2}, state.lang, 'or') end, }, ['and'] = { nDates = 2, ar='$date1 و $date2', ['be-tarask']='$date1 і $date2', bn='$date1 এবং $date2', ca='$date1 i $date2', cs='$date1 a $date2', da='$date1 og $date2', de='$date1 und $date2', el='$date1 και $date2', en='$date1 and $date2', ['en-gb']='$date1 and $date2', ['en-ca']='$date1 and $date2', eo='$date1 kaj $date2', es='$date1 y $date2', et='$date1 ja $date2', fa='$date1 و $date2', fi='$date1 ja $date2', fr='$date1 et $date2', gl='$date1 e $date2', he='$date1 ו- $date2', hu='$date1 és $date2', hsb='$date1 a $date2', it='$date1 e $date2', ja='$date1および$date2', mk='$date1 и $date2', ml='$date1 ഒപ്പം $date2', nb='$date1 og $date2', nn='$date1 og $date2', nds='$date1 un $date2', nl='$date1 en $date2', no='$date1 og $date2', pl='$date1 i $date2', pt='$date1 e $date2', qu='$date1wan $date2pas', ro='$date1 și $date2', ru='$date1 и $date2', sk='$date1 a $date2', sl='$date1 in $date2', sv='$date1 och $date2', uk='$date1 та $date2', ur='$date1 و $date2', vi='$date1 và $date2', ['zh-hans']='$date1和$date2', ['zh-hant']='$date1和$date2', default=function(date1, date2, state) return require("Module:Linguistic").conj({date1, date2}, state.lang, 'and') end, }, -- ========================================== -- === Prepositions ========================= -- ========================================== ['by'] = { nDates = 1, ar='حوالي $date1', ['be-tarask']={'да $date1', case={'gen',''}}, bn='$date1 কর্তৃক', ca='vers $date1', cs={'kolem $date1', case={'gen',''}}, da='mod $date1', de='spätestens $date1', el='έως $date1', en='by $date1', ['en-gb']='by $date1', ['en-ca']='by $date1', eo='ne post $date1', es='para $date1', et='hiljemalt $date1', fa='توسط $date1', fi={function(date1, state) return decYear(state,'fi','ill') .. '$date1 mennessä' end, case={'ill',''}}, fr='$date1 (au plus tard)', gl='cara a $date1', he='עד $date1', hr='do $date1', hsb={'do $date1', case={'gen',''}}, it='entro il $date1', ja='$date1まで', mk='кон $date1', ml='$date1-ൽ', nb='innen $date1', nn='innan $date1', nds='$date1 oder vördem al', nl='tegen $date1', no='innen $date1', pl={'przed $date1', case={'ins',''}}, pt='por $date1', qu="$date1 p'unchawkama", ro='de $date1', ru={'к $date1', case={'dat',''}}, sk={'okolo $date1', case={'gen',''}}, sl={function(date1, state) return 'najpozneje ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='senast $date1', uk={'до $date1', case={'dat',''}}, ur='توسط $date1', vi='vào $date1', -- need to insert "đã" somewhere later in the sentence --> ['zh-hans']='$date1前后', ['zh-hant']='$date1前后', default='<span style="color:red">by $date1</span>', }, ['before'] = { nDates = 1, ar='قبل $date1', ['be-tarask']={'перад $date1', case={'ins',''}}, bn='$date1-এর আগে', bg='Преди $date1', ca='abans $date1', cs={'před $date1', case={'ins',''}}, da='før $date1', de='vor $date1', el='πριν από $date1', en='before $date1', ['en-gb']='before $date1', ['en-ca']='before $date1', eo='antaŭ $date1', es='antes de $date1', et='enne $date1', fa='پیش از $date1', fi={function(date1, state) return 'ennen ' .. decYear(state,'fi','ptv') .. '$date1' end, case={'ptv',''}}, fr='avant $date1', gl='antes do $date1', he='לפני $date1', hr='prije $date1', hsb={'do $date1', case={'gen',''}}, hu='$date1 előtt', it='prima del $date1', ja='$date1より前', mk='пред $date1', ml='$date1-നു മുമ്പ്', nb='før $date1', nn='før $date1', nds='vör $date1', nl='voor $date1', no='før $date1', pl={'przed $date1', case={'ins',''}}, pt='antes de $date1', qu="$date1 p'unchaw ñawpan", ro='înainte de $date1', ru={'ранее $date1', case={'gen',''}}, sk={'pred $date1', case={'ins',''}}, sl={function(date1, state) return 'pred ' .. decYear(state,'sl','ins') .. ' $date1' end, case={'ins',''}}, sv='före $date1', uk={'до $date1', case={'gen',''}}, ur='قبل $date1', vi='trước $date1', ['zh-hans']='在$date1之前', ['zh-hant']='在$date1之前', default='<span style="color:red">before $date1</span>', }, ['from'] = { nDates = 1, ar='من $date1', ['be-tarask']={'з $date1', case={'gen',''}}, bn='$date1 থেকে', cs={'od $date1', case={'gen',''}}, de='Seit $date1', el='από $date1', en='from $date1', ['en-gb']='from $date1', ['en-ca']='from $date1', eo='ekde $date1', es='desde $date1', et='alates $date1', fa='از $date1', fi={function(date1, state) return decYear(state,'fi','ela') .. '$date1 alkaen' end, case={'ela',''}}, fr= function(date1, state) return 'à partir '.. frOf[state.precision] ..' $date1' end, gl='desde o $date1', he='מ- $date1', hr='od $date1', hsb={'wot $date1', case={'gen',''}}, it='dal $date1', ja='$date1から', nds='vonaf $date1', mk='од $date1', nb='fra $date1', nn='frå $date1', ml='$date1 മുതൽ', nl='vanaf $date1', no='fra $date1', pl={'od $date1', case={'gen',''}}, qu="$date1 p'unchawmanta", ro='din $date1', ru={'С $date1', case={'gen',''}}, sk={'od $date1', case={'gen',''}}, sl={function(date1, state) return 'od ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='från $date1', uk={'з $date1', case={'gen',''}}, ur='از $date1', vi='từ $date1', ['zh-hans']='自$date1', ['zh-hant']='自$date1', default='<span style="color:red">from $date1</span>', }, ['until'] = { nDates = 1, ['be-tarask']={'усутыч да $date1', case={'gen',''}}, bn='$date1 পর্যন্ত', cs={'do $date1', case={'gen', ''}}, de='bis $date1', en='until $date1', ['en-gb']='until $date1', ['en-ca']='until $date1', eo='ĝis $date1', es='hasta $date1', fr=function(date1, state) if state.precision > 10 then -- precision > month return "jusqu'au $date1" else return "jusqu'à $date1" end end, hr='do $date1', hsb={'do $date1', case={'gen',''}}, it='al $date1', nb= 'til $date1', nl= 'tot $date1', nn= 'til $date1', pl={'do $date1', case={'gen',''}}, ru={'вплоть до $date1', case={'gen',''}}, sk={'do $date1', case={'gen', ''}}, uk={'аж до $date1', case={'gen',''}}, ur='تک $date1', ['zh-hans']='直到$date1', ['zh-hant']='直到$date1', default='<span style="color:red">until $date1</span>', }, ['after'] = { nDates = 1, ar='بعد $date1', ['be-tarask']={'пасьля $date1', case={'gen',''}}, bn='$date1-এর পরে', ca='desprès $date1', cs={'po $date1', case={'loc',''}}, de='nach $date1', da='efter $date1', el='μετά από $date1', en='after $date1', ['en-gb']='after $date1', ['en-ca']='after $date1', eo='post $date1', es='después de $date1', et='pärast $date1', fa='پس از $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 jälkeen' end, case={'gen',''}}, fr='après $date1', gl='despois do $date1', he='לאחר $date1', hr='nakon $date1', hu='$date1 után', hsb={'po $date1', case={'loc',''}}, it='dopo il $date1', ja='$date1より後', mk='по $date1', ml='$date1-നു ശേഷം', nb='etter $date1', nn='etter $date1', nds='na $date1', nl='na $date1', no='etter $date1', pl={'po $date1', case={'loc',''}}, pt='após $date1', qu="$date1 p'unchaw qhipan", ro='după $date1', ru={'после $date1', case={'gen',''}}, sk={'po $date1', case={'loc',''}}, sl={function(date1, state) return 'po ' .. decYear(state,'sl','loc') .. ' $date1' end, case={'loc',''}}, sv='efter $date1', uk={'після $date1', case={'gen',''}}, ur='بعد $date1', vi='sau $date1', ['zh-hans']='在$date1之后', ['zh-hant']='在$date1之後', default='<span style="color:red">after $date1</span>', }, -- ========================================== -- === Adjectives =========================== -- ========================================== ['early'] = { nDates = 1, ar='بداية $date1', ['be-tarask']={'пачатак $date1', case={'gen',''}}, bn='$date1-এর শুরুতে', ca='al principi de $date1', cs={'začátek $date1', case={'gen',''}}, da='tidlig $date1', de='Anfang $date1', el='αρχές του $date1', en='early $date1', ['en-gb']='early $date1', ['en-ca']='early $date1', eo='komence de $date1', es='a principios de $date1', et='$date1 algus', fa='اوایل $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 alku' end, case={'gen',''}}, fr='début $date1', gl='a principios de $date1', he='תחילת $date1', hr='početak $date1', hsb={'spočatk $date1', case={'gen',''}}, hu='$date1 elején', it='inizio del $date1', ja='$date1初頭', mk='почеток на $date1', ml='$date1 ആദ്യപാദം', nb='tidlig $date1', nn='tidleg $date1', nds='Anfang $date1', nl='begin $date1', no='tidlig $date1', pl={'początek $date1', case={'gen',''}}, pt='a princípios de $date1', qu="$date1 ñawpaq p'unchawkunapi", ro='începând cu $date1', ru={'начало $date1', case={'gen',''}}, sk={'začiatok $date1', case={'gen',''}}, sl=function(date1, state)-- could actually be better should be "d'octobre à mars 2013' not "de octore 2013 à mars 2013" if state.precision == 9 then -- precision > month return 'zgodnje leto $date1' else -- "DE septebmbre" / "D'octobre" return 'zgodnji $date1' end end, sv='början av $date1', uk={'початок $date1', case={'gen',''}}, ur='ابتدا $date1', vi='đầu năm $date1', ['zh-hans']='$date1早期', ['zh-hant']='$date1早期', default='<span style="color:red">early $date1</span>', }, ['mid'] = { nDates = 1, ar='منتصف $date1', ['be-tarask']={'сярэдзіна $date1', case={'gen',''}}, bn='$date1-এর মাঝামাঝি', ca='a mitjan $date1', cs={'polovina $date1', case={'gen',''}}, da='midten af $date1', de='Mitte $date1', el='μέσα του $date1', en='mid $date1', ['en-gb']='mid $date1', ['en-ca']='mid $date1', eo='meze de $date1', es='a mediados de $date1', et='$date1 keskel', fa='اواسط $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 puoliväli' end, case={'gen',''}}, fr='mi $date1', gl='a mediados de $date1', he='אמצע $date1', hr='sredina $date1', hsb={'srjedź $date1', case={'gen',''}}, hu='$date1 közepén', it='metà del $date1', ja='$date1半ば', mk='средина на $date1', ml='$date1 മദ്ധ്യം', nb='midten av $date1', nn='midten av $date1', nds='Midd $date1', nl='midden $date1', no='midten av $date1', pl={'środek $date1', case={'gen',''}}, pt='meados de $date1', qu="$date1 chawpin p'unchawkunapi", ro='mijlocul lui $date1', ru={'середина $date1', case={'gen',''}}, sk={'polovica $date1', case={'gen',''}}, sl={function(date1, state) return 'sredina ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='mitten av $date1', uk={'середина $date1', case={'gen',''}}, ur='وسط $date1', vi='giữa năm $date1', ['zh-hans']='$date1中期', ['zh-hant']='$date1中期', default='<span style="color:red">mid $date1</span>', }, ['late'] = { nDates = 1, ar='نهاية $date1', bn='$date1-এর শেষে', ['be-tarask']={'канец $date1', case={'gen',''}}, ca='al final de $date1', cs='konec $date1', da='sen $date1', de='Ende $date1', el='τέλη του $date1', en='late $date1', ['en-gb']='late $date1', ['en-ca']='late $date1', eo='fine de $date1', es='a fines de $date1', et='$date1 lõpp', fa='اواخر $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 loppu' end, case={'gen',''}}, fr='fin $date1', gl='a finais de $date1', he='סוף $date1', hr='kraj $date1', hsb={'kónc $date1', case={'gen',''}}, hu='$date1 végén', it='fine del $date1', ja='$date1末', mk='крајот на $date1', ml='$date1 അന്ത്യപാദം', nb='sent $date1', no='seint $date1', nds='Enn $date1', nl='eind $date1', no='sent $date1', pl={'koniec $date1', case={'gen',''}}, pt='ao final de $date1', qu="$date1 qhipaq p'unchawkunapi", ro='sfârșitul lui $date1', ru={'конец $date1', case={'gen',''}}, sk={'koniec $date1', case={'gen',''}}, sl={function(date1, state) return 'pozno ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='slutet av $date1', uk={'кінець $date1', case={'gen',''}}, ur='اخیر $date1', vi='cuối năm $date1', ['zh-hans']='$date1晚期', ['zh-hant']='$date1晚期', default='<span style="color:red">late $date1</span>', }, ['circa'] = { nDates = 1, ar='حوالي $date1', ['be-tarask']={'каля $date1', case={'gen',''}}, bn='প্রায় $date1', ca='cap a $date1', cs='cca $date1', da='ca. $date1', de='etwa $date1', el='περ. $date1', en='circa $date1', ['en-gb']='circa $date1', ['en-ca']='circa $date1', eo='ĉirkaŭ $date1', es='hacia $date1', -- suggestion use "hacia"/"hacia el" or leave the latin circa or ca. et='ca. $date1', fa='حوالی $date1', -- template:Circa used 'حدود $date1' fi={function(date1, state) return 'suunnilleen ' .. decYear(state,'fi','ine') .. '$date1' end, case={'ine',''}}, -- template:Circa used 'noin $date1' fr=function(date1, state) if state.precision >= 11 then -- precision >= day return 'vers le $date1' else return 'vers $date1' end end, gl='entre $date1', -- template:Circa used 'cara a $date1' he='בסביבות $date1', hr='oko $date1', hsb={'wokoło $date1', case={'gen',''}}, hu='$date1 körül', it='$date1 circa', ja='$date1頃', ko='$date1경', mk='~ $date1', -- template:Circa used 'o. $date1' nb='ca. $date1', nn='ca. $date1', nds='üm un bi $date1', nl='ca. $date1', no='ca. $date1', pl={'około $date1', case={'gen',''}}, pt='cerca de $date1', qu='$date1chá', ro='circa $date1', ru={'около $date1', case={'gen',''}}, sk='cca $date1', sl={function(date1, state) return 'ok. ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='c:a $date1', -- template:Circa used 'ca $date1' uk={'близько $date1', case={'gen', ''}}, ur='قریباً $date1', vi='vào khoảng $date1', ['zh-hans']='约$date1', ['zh-hant']='約$date1', default='<span style="color:red">circa $date1</span>', }, ['uncertain'] = { nDates = 1, ['zh-hans']='$date1(?)', ['zh-hant']='$date1(?)', default='$date1 (?)', }, probably = { -- see Q56644435 nDates = 1, ast = 'probablemente $date1', bn = 'সম্ভবত $date1', ca = 'probablement $date1', cs = 'pravděpodobně $date1', de = 'wahrscheinlich $date1', el = 'πιθανόν $date1', en = 'probably $date1', ['en-gb']='probably $date1', ['en-ca']='probably $date1', eo = 'probable $date1', es = 'probable $date1', fa = 'احتمالاً $date1', fr = 'probablement $date1', he = 'כפי הנראה $date1', hu = 'feltehetőleg $date1', it = 'probabile $date1', mk = 'веројатно $date1', nl = 'waarschijnlijk $date1', pl = 'prawdopodobnie $date1', pt = 'provavelmente $date1', ru = 'вероятно $date1', sv = 'antagligen $date1', default='<span style="color:red">probably $date1</span>', }, possibly = { -- see Q30230067 nDates = 1, ast = 'posiblemente $date1', bn = 'যথাসম্ভব $date1', cs = 'možná $date1', de = 'möglicherweise $date1', en = 'possibly $date1', ['en-gb']='possibly $date1', ['en-ca']='possibly $date1', eo = 'eble $date1', el = 'πιθανόν $date1', fa = 'احتمالاً $date1', fr = 'peut-être $date1', hu = 'talán $date1', mk = 'можеби $date1', nl = 'mogelijk $date1', pl = 'być może $date1', pt = 'possivelmente $date1', ro = 'poate $date1', ru = 'возможно $date1', sv = 'möjligen $date1', default='<span style="color:red">possibly $date1</span>', }, presumably = { -- see Q18122778 nDates = 1, ast = 'presumiblemente $date1', de = 'vermutlich $date1', en = 'presumably $date1', ['en-gb']='presumably $date1', ['en-ca']='presumably $date1', fr = 'présumé $date1', it = 'presumibilmente $date1', ru = 'предположительно $date1', pl = 'przypuszczalnie $date1', default='<span style="color:red">presumably $date1</span>', }, ['year unknown']= { nDates = 0, ca='Any desconegut', ['be-tarask']='Год невядомы', bn='অজানা বছর', cs='neznámý rok', de='Jahr unbekannt', el='άγνωστο έτος', en='year unknown', ['en-gb']='year unknown', ['en-ca']='year unknown', eo='jaro nesciata', es='Año desconocido', fa='سال نامعلوم', fi='tuntematon vuosi', fr='Année inconnue', he='שנה לא ידועה', hsb='lěto njeznate', hr='nepoznata godina', it='anno sconosciuto', ja='年代不明', la='Sine anno', ml='വർഷം ലഭ്യമല്ല', mk='непозната година', nb='ukjent år', nn='ukjent år', nl='zonder jaar', no='ukjent år', pl='rok nieznany', qu='Mana riqsisqa wata', ru='Год неизвестен', sk='neznámy rok', sl='neznano leto', sv='Okänt år', uk='рік невідомий', ur='سال نامعلوم', vi='không rõ năm', ['zh-hans']='年份未知', ['zh-hant']='年份未知', default='<span style="color:red">year unknown</span>', }, -- ========================================== -- === Parts of a whole ===================== -- ========================================== ['firsthalf'] = { nDates = 1, ar='النصف الأول من $date1', ['be-tarask']={'першая палова $date1', case={'gen',''}}, bn='$date1-এর প্রথমার্ধ', ca='1a meitat de $date1', cs={'1. polovina $date1', case={'gen',''}}, da='1. halvdel af $date1', de='1. Hälfte $date1', el='πρώτο μισό του $date1', en='first half of $date1', ['en-gb']='first half of $date1', ['en-ca']='first half of $date1', eo='unua duono de $date1', es='primera mitad de $date1', et='$date1 esimene pool', fa='نیمهٔ نخست $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 alkupuolisko' end, case={'gen',''}}, fr='1<sup>re</sup> moitié de $date1', gl='primeira metade de $date1', he='במחצית הראשונה של $date1', hsb={'prěnja połojca $date1', case={'gen',''}}, hu='$date1 első felében', hr='prva polovina $date1', it='prima metà del $date1', ja='$date1上半期', mk='прва половина на $date1', ml='$date1 ആദ്യപകുതി', nb='første halvdel av $date1', nn='fyrste halvdelen av $date1', nds='1. Helft $date1', nl='eerste helft $date1', no='første halvdel av $date1', pl={'pierwsza połowa $date1', case={'gen',''}}, pt='primeira metade de $date1', qu='$date1 ñawpaq kuskanpi', ro='prima jumătate a lui $date1', ru={'первая половина $date1', case={'gen',''}}, sk={'1. polovica $date1', case={'gen',''}}, sl={function(date1, state) return 'prva polovica ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='första halvan av $date1', uk={'перша половина $date1', case={'gen',''}}, ur='نصف اول $date1', vi='nửa đầu năm $date1', ['zh-hans']='$date1上半期', ['zh-hant']='$date1上半期', default='<span style="color:red">first half of $date1</span>', }, ['secondhalf'] = { nDates = 1, ar='النصف الثاني من $date1', ['be-tarask']={'другая палова $date1', case={'gen',''}}, bn='$date1-এর দ্বিতীয়ার্ধ', ca='2a meitat de $date1', cs={'2. polovina $date1', case={'gen',''}}, da='2. halvdel af $date1', de='2. Hälfte $date1', el='δεύτερο μισό του $date1', en='second half of $date1', ['en-gb']='second half of $date1', ['en-ca']='second half of $date1', eo='dua duono de $date1', es='segunda mitad de $date1', et='$date1 teine pool', fa='نیمهٔ دوم $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 loppupuolisko' end, case={'gen',''}}, fr='2<sup>e</sup> moitié de $date1', gl='segunda metade de $date1', he='במחצית השנייה של $date1', hsb={'druha połojca $date1', case={'gen',''}}, hr='druga polovina $date1', hu='$date1 második felében', it='seconda metà del $date1', ja='$date1下半期', mk='втора половина на $date1', ml='$date1 രണ്ടാം പകുതി', nb='andre halvdel av $date1', nn='andre halvdelen av $date1', nds='2. Helft vun $date1', nl='tweede helft $date1', no='andre halvdel av $date1', pl={'druga połowa $date1', case={'gen',''}}, pt='segunda metade de $date1', qu='$date1 qhipaq kuskanpi', ro='a doua jumătate a lui $date1', ru={'вторая половина $date1', case={'gen',''}}, sk={'2. polovica $date1', case={'gen',''}}, sl={'druga polovica {{IfNum | $date0 | leta}} $date1', case={'gen',''}}, sv='andra halvan av $date1', uk={'друга половина $date1', case={'gen',''}}, ur='نصف آخر $date1', vi='nửa cuối năm $date1', ['zh-hans']='$date1下半期', ['zh-hant']='$date1下半期', default='<span style="color:red">second half of $date1</span>', }, ['1quarter']= { nDates = 1, bn='$date1-এর প্রথম ত্রৈমাসিক', ['be-tarask']={'першая чвэрць $date1', case={'gen',''}}, cs={'1. čtvrtina $date1', case={'gen',''}}, de='erstes Viertel $date1', en='first quarter of $date1', ['en-gb']='first quarter of $date1', ['en-ca']='first quarter of $date1', eo='unua kvarono de $date1', es='primer cuarto del $date1', fa='ربع نخست $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 ensimmäinen neljännes' end, case={'gen',''}}, fr= function(date1, state) return 'premier quart '.. frOf[state.precision] ..' $date1' end, he='רבעון ראשון של $date1', hsb={'prěnja štwórćina $date1', case={'gen',''}}, hr='prva četvrtina $date1', it='primo quarto del $date1', ja='$date1第1四半期', nb='første kvartal av $date1', nl='eerste kwart $date1', nn='fyrste kvartalet av $date1', no='første kvartal av $date1', pl={'pierwsza ćwiartka $date1', case={'gen',''}}, qu='$date1 ñawpaq ñiqin tawa phatmanpi', ru={'первая четверть $date1', case={'gen',''}}, sk={'1. štvrtina $date1', case={'gen',''}}, sl={'prva četrtina {{IfNum | $date0 | leta}} $date1', case={'gen',''}}, sl={function(date1, state) return 'prva četrtina ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='första kvartalet av $date1', uk={'1-ша чверть $date1', case={'gen',''}}, ur='پہلی سہ ماہی $date1', vi='quý 1 năm $date1', ['zh-hans']='$date1第一季度', ['zh-hant']='$date1第一季度', default='<span style="color:red">first quarter of $date1</span>', }, ['2quarter']= { nDates = 1, ['be-tarask']={'другая чвэрць $date1', case={'gen',''}}, bn='$date1-এর দ্বিতীয় ত্রৈমাসিক', cs={'2. čtvrtina $date1', case={'gen',''}}, de='zweites Viertel $date1', en='second quarter of $date1', ['en-gb']='second quarter of $date1', ['en-ca']='second quarter of $date1', eo='dua kvarono de $date1', es='segundo cuarto del $date1', fa='ربع دوم $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 toinen neljännes' end, case={'gen',''}}, fr= function(date1, state) return 'deuxième quart '.. frOf[state.precision] ..' $date1' end, he='רבעון שני של $date1', hsb={'druha štwórćina $date1', case={'gen',''}}, hr='druga četvrtina $date1', it='secondo quarto del $date1', ja='$date1第2四半期', nb='andre kvartal av $date1', nl='tweede kwart $date1', nn='andre kvartalet av $date1', no='andre kvartal av $date1', pl={'druga ćwiartka $date1', case={'gen',''}}, qu='$date1 iskay ñiqin tawa phatmanpi', ru={'вторая четверть $date1', case={'gen',''}}, sk={'2. štvrtina $date1', case={'gen',''}}, sl={function(date1, state) return 'druga četrtina ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='andra kvartalet av $date1', uk={'2-га чверть $date1', case={'gen',''}}, ur='دوسری سہ ماہی $date1', vi='quý 2 năm $date1', ['zh-hans']='$date1第二季度', ['zh-hant']='$date1第二季度', default='<span style="color:red">second quarter of $date1</span>', }, ['3quarter']= { nDates = 1, ['be-tarask']={'трэцяя чвэрць $date1', case={'gen',''}}, bn='$date1-এর তৃতীয় ত্রৈমাসিক', cs={'3. čtvrtina $date1', case={'gen',''}}, de='drittes Viertel $date1', en='third quarter of $date1', ['en-gb']='third quarter of $date1', ['en-ca']='third quarter of $date1', eo='tria kvarono de $date1', es='tercer cuarto del $date1', fa='ربع سوم $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 kolmas neljännes' end, case={'gen',''}}, fr= function(date1, state) return 'troisième quart '.. frOf[state.precision] ..' $date1' end, he='רבעון שלישי של $date1', hsb={'třeća štwórćina $date1', case={'gen',''}}, hr='treća četvrtina $date1', it='terzo quarto del $date1', ja='$date1第3四半期', nb='tredje kvartal av $date1', nl='derde kwart $date1', nn='tredje kvartalet av $date1', no='tredje kvartal av $date1', pl={'trzecia ćwiartka $date1', case={'gen',''}}, qu='$date1 kimsa ñiqin tawa phatmanpi', sk={'3. štvrtina $date1', case={'gen',''}}, sl={function(date1, state) return 'tretja četrtina ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, ru={'третья четверть $date1', case={'gen',''}}, sv='tredje kvartalet av $date1', uk={'3-тя чверть $date1', case={'gen',''}}, ur='تیسری سہ ماہی $date1', vi='quý 3 năm $date1', ['zh-hans']='$date1第三季度', ['zh-hant']='$date1第三季度', default='<span style="color:red">third quarter of $date1</span>', }, ['4quarter']= { nDates = 1, ['be-tarask']={'чацьвёртая чвэрць $date1', case={'gen',''}}, bn='$date1-এর চতুর্থ ত্রৈমাসিক', cs={'4. čtvrtina $date1', case={'gen',''}}, de='letztes Viertel $date1', en='fourth quarter of $date1', ['en-gb']='fourth quarter of $date1', ['en-ca']='fourth quarter of $date1', eo='kvara kvarono de $date1', es='último cuarto del $date1', fa='ربع چهارم $date1', fi={function(date1, state) return decYear(state,'fi','gen') .. '$date1 viimeinen neljännes' end, case={'gen',''}}, fr= function(date1, state) return 'quatrième quart '.. frOf[state.precision] ..' $date1' end, he='רבעון רביעי של $date1', hsb={'poslednja štwórćina $date1', case={'gen',''}}, hr='četvrta četvrtina $date1', it='quarto quarto del $date1', ja='$date1第4四半期', nb='fjerde kvartal av $date1', nl='vierde kwart $date1', nn='tredje kvartalet av $date1', no='fjerde kvartal av $date1', pl={'czwarta ćwiartka $date1', case={'gen',''}}, qu='$date1 qhipaq ñiqin tawa phatmanpi', ru={'последняя четверть $date1', case={'gen',''}}, sk={'4. štvrtina $date1', case={'gen',''}}, sl={function(date1, state) return 'zadnja četrtina ' .. decYear(state,'sl','gen') .. ' $date1' end, case={'gen',''}}, sv='fjärde kvartalet av $date1', uk={'4-та чверть $date1', case={'gen',''}}, ur='چوتھی سہ ماہی $date1', vi='quý 4 năm $date1', ['zh-hans']='$date1第四季度', ['zh-hant']='$date1第四季度', default='<span style="color:red">forth quarter of $date1</span>', }, -- ========================================== -- === Seasons ============================== -- ========================================== ['spring'] = { nDates = 1, ar='ربيع $date1', ['be-tarask']='вясна $date1', bn='বসন্তকাল $date1', ca='primavera $date1', cs={'jaro $date1', case={'gen', ''}}, da='Forår $date1', de='Frühling $date1', en='Spring $date1', ['en-gb']='Spring $date1', ['en-ca']='Spring $date1', eo='printempo $date1', es='primavera de $date1', et='$date1 kevad', fa='بهار $date1', fi='Kevät $date1', fr='printemps $date1', gl='primavera $date1', he='אביב $date1', hr='proljeće $date1', hsb='nalěćo $date1', hu='$date1 tavasza', it='primavera $date1', ja='{{#if:$date1|$date1年}}春', mk='пролет $date1', ml='$date1 വസന്തം', nb='våren $date1', nds='Vörjohr $date1', nn='våren $date1', nl='voorjaar $date1', no='våren $date1', pl='wiosna $date1', pt='primavera de $date1', ro='primăvara lui $date1', ru='весна $date1', sk={'jar $date1', case={'gen', ''}}, sl='pomlad $date1', sv='våren $date1', uk='весна $date1', ur='بہار $date1', vi='mùa đông năm $date1', ['zh-hans']='{{#if:$date1|$date1年}}春季', ['zh-hant']='{{#if:$date1|$date1年}}春季', default='<span style="color:red">Spring $date1</span>', }, ['summer'] = { nDates = 1, ar='صيف $date1', ['be-tarask']='лета $date1', bn='গ্রীষ্মকাল $date1', ca='estiu $date1', cs={'léto $date1', case={'gen', ''}}, da='Sommer $date1', de='Sommer $date1', en='Summer $date1', ['en-gb']='Summer $date1', ['en-ca']='Summer $date1', eo='somero $date1', es='verano de $date1', et='$date1 suvi', fa='تابستان $date1', fi='Kesä $date1', fr='été $date1', gl='verán $date1', he='קיץ $date1', hr='ljeto $date1', hsb='lěćo $date1', hu='$date1 nyara', it='estate $date1', ja='{{#if:$date1|$date1年}}夏', mk='лето $date1', ml='$date1 വേനൽ', nb='sommeren $date1', nds='Sommer $date1', nn='sumaren $date1', nl='zomer $date1', no='sommeren $date1', pl='lato $date1', pt='verão de $date1', ro='vara lui $date1', ru='лето $date1', sk={'leto $date1', case={'gen', ''}}, sl='poletje $date1', sv='sommaren $date1', uk='літо $date1', ur='گرما $date1', vi='mùa hè năm $date1', ['zh-hans']='{{#if:$date1|$date1年}}夏季', ['zh-hant']='{{#if:$date1|$date1年}}夏季', default='<span style="color:red">Summer $date1</span>', }, ['autumn'] = { nDates = 1, ar='خريف $date1', ['be-tarask']='восень $date1', bn='শরত্কাল $date1', ca='tardor $date1', cs={'podzim $date1', case={'gen', ''}}, da='Efterår $date1', de='Herbst $date1', en='Autumn $date1', ['en-gb']='Autumn $date1', ['en-ca']='Autumn $date1', eo='aŭtuno $date1', es='otoño de $date1', et='$date1 sügis', fa='پاییز $date1', fi='Syksy $date1', fr='automne $date1', gl='outono $date1', he='סתיו $date1', hr='jesen $date1', hsb='nazyma $date1', hu='$date1 ősze', it='autunno $date1', ja='{{#if:$date1|$date1年}}秋', mk='есен $date1', ml='$date1 ശരത്കാലം', nb='høsten $date1', nds='Harvst $date1', nn='hausten $date1', nl='herfst $date1', no='høsten $date1', pl='jesień $date1', pt='outono de $date1', ro='toamna lui $date1', ru='осень $date1', sk={'jeseň $date1', case={'gen', ''}}, sl='jesen $date1', sv='hösten $date1', uk='осінь $date1', ur='خزاں $date1', vi='mùa thu năm $date1', ['zh-hans']='{{#if:$date1|$date1年}}秋季', ['zh-hant']='{{#if:$date1|$date1年}}秋季', default='<span style="color:red">Autumn $date1</span>', }, ['winter'] = { nDates = 1, ar='شتاء $date1', ['be-tarask']='зіма $date1', bn='শীতকাল $date1', ca='hivern $date1', cs={'zima $date1', case={'gen', ''}}, da='Vinter $date1', de='Winter $date1', en='Winter $date1', ['en-gb']='Winter $date1', ['en-ca']='Winter $date1', eo='vintro $date1', es='invierno de $date1', et='$date1 talv', fa='زمستان $date1', fi='Talvi $date1', fr='hiver $date1', gl='inverno $date1', he='חורף $date1', hr='zima $date1', hsb='zyma $date1', hu='$date1 tele', it='inverno $date1', ja='{{#if:$date1|$date1年}}冬', mk='зима $date1', ml='$date1 ശൈത്യകാലം', nds='Winter $date1', nl='winter $date1', nb='vinteren $date1', nn='vinteren $date1', no='vinteren $date1', pl='zima $date1', pt='inverno de $date1', ro='iarna lui $date1', ru='зима $date1', sk={'zima $date1', case={'gen', ''}}, sl='zima $date1', sv='vintern $date1', uk='зима $date1', ur='سرما $date1', vi='mùa đông năm $date1', ['zh-hans']='{{#if:$date1|$date1年}}冬季', ['zh-hant']='{{#if:$date1|$date1年}}冬季', default='<span style="color:red">Winter $date1</span>', }, -- ========================================== -- === Decade/Century/Millennium ============ -- ========================================== ['decade'] = { nDates = 1, ar='أعوام $date1', ['be-tarask']='$date1-я гады', bn='$date1-এর দশক', ca='dècada del $date1', cs=function(date1, state) return ((date1 % 100 == 0) and 'první dekáda' or ((date1 % 100) .. '. léta')) .. ' ' .. (math.floor(date1 / 100) + 1) .. '. století' end, da="$date1'erne", de='$date1er-Jahre', el='δεκαετία του $date1', en='$date1s', ['en-gb']='$date1s', ['en-ca']='$date1s', eo='$date1-aj jaroj', es='años $date1', et='$date1ndad', fa='دههٔ $date1', fi='$date1-luvulla', fr='années $date1', gl='anos $date1', he='שנות ה-$date1', hr='$date1-ih', hsb='$date1te lěta', hu='$date1-s évek', it="{{#ifexpr: $date1 mod 100 = 0 | primo decennio del {{Roman|{{#expr: ($date1 / 100) + 1}}}} sec. | anni '{{#expr: $date1 mod 100 }} del {{Roman|{{#expr: floor($date1 / 100) + 1}}}} sec.}}", ja='$date1年代', mk='$date1-ти', ml='ദശകം $date1-ൽ', nb='$date1-årene', nn='$date1-åra', nds='Johren $date1', nl='jaren $date1', no='$date1-årene', pl=function(date1, state) local str = 'lata '..(date1 % 100)..'. ' if (date1 % 100 == 0) then str = 'pierwsza dekada ' elseif (date1 % 100 == 10) then str = 'druga dekada ' end return str .. Roman(math.floor(date1 / 100) + 1) .. ' wieku' end, pt='década de $date1', qu='$date1 watakuna', ro='anii $date1', ru='$date1-е годы', sk=function(date1, state) return ((date1 % 100 == 0) and 'prvé desaťročie' or ((date1 % 100) .. '. roky')) .. ' ' .. (math.floor(date1 / 100) + 1) .. '. storočia' end, sl='$date1-ta leta', sv='$date1-talet{{#switch:$date1|1300|1400|1500|1600|1700|1800|1900|2000|2100=&nbsp;(decennium)}}', uk='$date1-ті роки', ur='دہائی $date1', vi='thập niên $date1', ['zh-hans']='$date1年代', ['zh-hant']='$date1年代', default='<span style="color:red">$date1s</span>', }, ['century'] = { nDates = 1, ar='القرن $date1', ['be-tarask']=function(date1, state) return Ordinal(date1, 'be-tarask') .. ' стагодзьдзе' end, bn=function(date1, state) return Ordinal(date1, 'bn') .. ' শতাব্দী' end, ca='segle {{small-caps|{{lc:{{Roman year|$date1}}}}}}', cs='$date1. století', da='$date1. århundrede', de='$date1. Jahrhundert', el='$date1ος αιώνας', en=function(date1, state) return Ordinal(date1, 'en') .. ' century' end, ['en-gb']=function(date1, state) return Ordinal(date1, 'en-gb') .. ' century' end, ['en-ca']=function(date1, state) return Ordinal(date1, 'en-ca') .. ' century' end, eo='$date1-a jarcento', es=function(date1, state) return 'siglo ' .. Roman(date1) end, et='$date1. sajand', fa='سدهٔ $date1', fi='{{#expr: ($date1 - 1) * 100}}-luvulla', fr=function(date1, state) return Ordinal(date1, 'fr', 'roman', 'm') .. ' siècle' end, gl=function(date1, state) return 'século ' .. Roman(date1) end, he='המאה ה-$date1', hr='$date1. stoljeće', hsb='$date1. lětstotk', hu='$date1. évszázad', it=function(date1, state) return Roman(date1) .. ' sec.' end, ja='$date1世紀', la='saeculum $date1', mk=function(date1, state) return Roman(date1) .. ' век' end, ml='$date1-ആം നൂറ്റാണ്ട്', nb=function(date1, state) return Ordinal(date1, 'nb') .. ' århundre' end, nn=function(date1, state) return 'det ' .. Ordinal(date1, 'no') .. ' århundre' end, nds='$date1. Johrhunnert', nl='$date1e eeuw', no=function(date1, state) return Ordinal(date1, 'no') .. ' århundre' end, pl=function(date1, state) return Roman(date1) .. ' ' .. decCentury('pl',state.case) end, pt=function(date1, state) return 'século ' .. Roman(date1) end, qu='$date1 ñiqin pachakwata', ro='secolul al $date1-lea', ru=function(date1, state) return Roman(date1) .. ' век' end, sk='$date1. storočie', sl=function(date1, state) return Ordinal(date1, 'sl') .. '. stoletje' end, sv='{{#expr:$date1 - 1}}00-talet', tt=function(date1, state) return Roman(date1) .. ' гасыр' end, uk=function(date1, state) return Roman(date1) .. ' ст.' end, ur='صدی $date1', vi='thế kỷ $date1', ['zh-hans']='$date1世纪', ['zh-hant']='$date1世紀', default='<span style="color:red">$date1 century</span>', }, ['millennium'] = { nDates = 1, ['be-tarask']=function(date1, state) return Ordinal(date1, 'be-tarask') .. ' тысячагодзьдзе' end, bn=function(date1, state) return Ordinal(date1, 'bn') .. ' সহস্রাব্দ' end, cs='$date1. tisíciletí', de='$date1. Jahrtausend', en=function(date1, state) return Ordinal(date1, 'en') .. ' millennium' end, ['en-gb']=function(date1, state) return Ordinal(date1, 'en-gb') .. ' millennium' end, ['en-ca']=function(date1, state) return Ordinal(date1, 'en-ca') .. ' millennium' end, eo='$date1-a jarmilo', es=function(date1, state) return Roman(date1) .. ' milenio' end, fa=function(date1, state) return 'هزارهٔ ' .. Ordinal(date1, 'fa') end, fr=function(date1, state) return Ordinal(date1, 'fr', 'roman', 'm') .. ' millénaire' end, hr='$date1. tisućljeće', hsb='$date1. lěttysac', it=function(date1, state) return Roman(date1) .. ' millennio' end, ja='$date1千年紀', la='millennium $date1', nb=function(date1, state) return Ordinal(date1, 'nb') .. ' årtusen' end, nn=function(date1, state) return Ordinal(date1, 'no') .. ' tusenår' end, nl='$date1e millennium', no=function(date1, state) return Ordinal(date1, 'no') .. ' årtusen' end, pl=function(date1, state) return Roman(date1) .. ' ' .. decMillennium('pl',state.case) end, pt=function(date1, state) return Roman(date1) .. ' milénio' end, qu='$date1 ñiqin waranqawata', ru=function(date1, state) return Roman(date1) .. ' тысячелетие' end, sk='$date1. tisícročie', sl=function(date1, state) return Ordinal(date1, 'sl') .. '. tisočletje' end, sv=function(date1, state) return Ordinal(date1, 'sv') .. ' årtusendet' end, uk=function(date1, state) return Roman(date1) .. ' тис.' end, ur=function(date1, state) return 'ہزارہ ' .. Ordinal(date1, 'ur') end, vi='thiên niên kỷ $date1', ['zh-hans']=function(date1, state) return Ordinal(date1, 'zh-hans') .. '千年' end, ['zh-hant']=function(date1, state) return Ordinal(date1, 'zh-hant') .. '千年' end, --default='{{Please translate|$date1 millennium|Module:I18n/complex date}}', default='<span style="color:red">$date1 millennium</span>', }, ['million'] = { de = '$date1 Millionen Jahre', en = '$date1 million years', ['en-gb'] = '$date1 million years', ['en-ca'] = '$date1 million years', eo = '$date1 milionoj da jaroj', es = '$date1 millones de años', nl = '$date1e miljoen jaar', fr = '$date1 millions d’années', it = '$date1 milioni di anni', nb = '$date1 millioner år', nl = '$date1 miljoen jaar', nn = '$date1 millionar år', pl = '$date1 milionów lat', pt = '$date1 milhões de anos', ru = '$date1 миллиона лет', uk = '$date1 мільйони років', ur = '$date1 ملین سال', ['zh-hans'] = '$date1百万年', ['zh-hant'] = '$date1百万年', default='<span style="color:red">$date1 million years</span>', nDates = 1, }, ['billion'] = { de = '$date1 Milliarden Jahre', en = '$date1 billion years', ['en-gb'] = '$date1 billion years', ['en-ca'] = '$date1 billion years', es = '$date1 mil millones de años', nl = '$date1e miljard jaar', fr = '$date1 milliard d’années', it = '$date1 miliardi di anni', nb = '$date1 milliarder år', nl = '$date1 miljard jaar', nn = '$date1 milliardar år', pl = '$date1 miliardów lat', pt = '$date1 mil milhões de anos', ru = '$date1 миллиардов лет', uk = '$date1 мільярдів років', ur = '$date1 بلین سال', ['zh-hans'] = '$date1十亿年', ['zh-hant'] = '$date1十億年', default='<span style="color:red$date1 billion years</span>', nDates = 1, }, -- ========================================== -- === Complex phrases ====================== -- ========================================== -- Phrases which for some languages can be build out of simpler phrases -- Their "default" state, used when no translation in the requested language was found, returns a "state" like -- table which is used to call the function again and built the phrase out of simple phrases -- $date1 - original date - 1 -- $date2 - original date -- if era is BC than $date1 and $date2 are swapped ['turn of the century'] = { nDates = 2, ['be-tarask']=function(date1, date2, state) return 'канец ' .. Roman(date1) ..' — пачатак ' .. Roman(date2) ..' стагодзьдзя' end, bn=function(date1, date2, state) return '$date1/' .. Ordinal(date2, 'bn') .. ' শতাব্দীর পালাবদলে' end, cs='přelom $date1. a $date2. století', de=function(date1, date2, state) return 'Jahrhundertwende $date1/' .. Ordinal(date2, 'de') end, en=function(date1, date2, state) return 'turn of the $date1/' .. Ordinal(date2, 'en') .. ' century' end, ['en-gb']=function(date1, date2, state) return 'turn of the $date1/' .. Ordinal(date2, 'en-gb') .. ' century' end, ['en-ca']=function(date1, date2, state) return 'turn of the $date1/' .. Ordinal(date2, 'en-ca') .. ' century' end, eo='ŝanĝo de la $date1-a al la $date2-a jarcentoj', es=function(date1, date2, state) return 'hacia finales del siglo ' .. Roman(date1) .. ' y principios del siglo ' .. Roman(date2) .. '' end, fi='{{#expr: $date1 * 100-100}}-luvun loppu ja {{#expr: $date2 * 100-100}}-luvun alku', fr=function(date1, date2, state) return 'fin du ' .. Ordinal(date1, 'fr', 'roman', 'm') .. ' siècle / début du ' .. Ordinal(date2, 'fr', 'roman', 'm') end, hr='kraj $date1. i početak $date2. stoljeća', hsb=function(date1, date2, state) return 'přechod ' .. Roman(date1) ..' do ' .. Roman(date2) ..' lětstotka' end, it=function(date1, date2, state) return 'fine del ' .. Roman(date1) .. ' sec. e inizio del ' .. Roman(date2) .. ' sec.' end, ja='$date1世紀から$date2世紀への変わり目', nb=function(date1, date2, state) return 'slutten av det ' .. Ordinal(date1, 'nb') .. ' århundre/begynnelsen av det ' .. Ordinal(date2, 'nb') .. ' århundre' end, nl=function(date1, date2, state) return 'eind $date1e/begin $date2e eeuw' end, nn=function(date1, date2, state) return 'slutten av det ' .. Ordinal(date1, 'nn') .. ' hundreåret/byrjinga av det ' .. Ordinal(date2, 'nn') .. ' hundreåret' end, pl=function(date1, date2, state) return 'przełom ' .. Roman(date1) ..' i ' .. Roman(date2) ..' wieku' end, qu="$date1 ñiqin waranqawatamanta $date2 ñiqin waranqawataman t'ikrasqanpi", ru=function(date1, date2, state) return 'конец ' .. Roman(date1) ..' — начало ' .. Roman(date2) ..' века' end, sk='prelom $date1. a $date2. storočia', sl=function(date1, date2, state) return 'pozno ' .. Ordinal(date1, 'sl') .. '. in zgodnje ' .. Ordinal(date2, 'sl') .. '. stoletje' end, sv=function(date1, date2, state) return '$date1/' .. Ordinal(date2, 'sv') .. ' årtusendets sekelskifte' end, uk=function(date1, date2, state) return 'кін. ' .. Roman(date1) ..' ст. — поч. ' .. Roman(date2) ..' ст.' end, vi='bước sang thế kỷ $date2', ['zh-hans']=function(date1, date2, state) return '$date1世纪末' .. Ordinal(date2, 'zh-hans') .. '世纪初' end, ['zh-hant']=function(date1, date2, state) return '$date1世紀末' .. Ordinal(date2, 'zh-hant') .. '世紀初' end, default=function(date1, date2, state) return {conj='and', adj1 = 'late', unit1='century', era1=state.era1, adj2 = 'early', unit2='century', era2=state.era2} end, }, -- $date1 - original date - 10 -- $date2 - original date -- if era is BC than $date1 and $date2 are swapped ['turn of the decade']={ nDates = 2, ['be-tarask']='канец $date1-х — пачатак $date2-х гг.', bn='$date1-এর দশকের শেষে এবং $date2-এর দশকের শুরুতে', cs=function(date1, date2, state) local decade1 = math.floor((date1 % 100) / 10) local decade2 = math.floor((date2 % 100) / 10) local century1 = math.floor( date1 / 100) + 1 local century2 = math.floor( date2 / 100) + 1 if decade1 == 0 and date1 < date2 then return "přelom 1. a 2. dekády " .. century1 .. ". století" elseif decade2 == 0 and date2 < date1 then return "přelom 9. a 10. dekády " .. century1 .. ". století" elseif (decade1 == 9 and date1 < date2) or (decade2 == 9 and date2 < date1) then return "přelom " .. century1 .. ". a " .. century2 .. ". století" else return "přelom " .. decade1 .. "0. a " .. decade2 .. "0. let " .. century1 .. ". století" end end, de='späte $date1er und frühe $date2er', en='late $date1s and early $date2s', ['en-gb']='late $date1s and early $date2s', ['en-ca']='late $date1s and early $date2s', eo='ŝanĝo de la $date1-a al la $date2-a jardekoj', es='finales de los años $date1 y principios de los años $date2', fa='اواخر دههٔ $date1 و اوایل دههٔ $date2', fi='$date1-luvun loppu ja $date2-luvun alku', fr='fin des années $date1 / début des années $date2', hr='kraj $date1-ih i početak $date2-ih', hsb='pózdnje $date1te a zažne $date2te lěta', it='fine degli anni $date1 / inizio degli anni $date2', ja='$date1年代末から$date2年代初頭', nb = 'sent på $date1-tallet og tidlig på $date2-tallet', nl = 'eind $date1e/begin $date2e decennium', nn = 'seint på $date1-talet og tidleg på $date2-talet', pl=function(date1, date2, state) local decade1 = math.floor(date1 % 100) local decade2 = math.floor(date2 % 100) local century1 = Roman(math.floor( date1 / 100) + 1) local century2 = Roman(math.floor( date2 / 100) + 1) if decade1 == 0 and date1 < date2 then return "przełom pierwszej i drugiej dekady " .. century1 .. " wieku" elseif decade1 == 10 and date1 < date2 then return "przełom drugiej dekady i lat 20. " .. century1 .. " wieku" elseif decade1 == 90 and decade2 == 0 then return "przełom ostatniej dekady " .. century1 .. " i pierwszej dekady " .. century2 .. " wieku" else return "przełom lat " .. decade1 .. ". i " .. decade2 .. ". " .. century1 .. " wieku" end end, qu='qhipaq $date1 watakuna ñawpaq $date2 watakunapas', ru='конец $date1-х — начало $date2-х гг.', sv='sena $date1-talet och tidiga $date2-talet', sk=function(date1, date2, state) local decade1 = math.floor((date1 % 100) / 10) local decade2 = math.floor((date2 % 100) / 10) local century1 = math.floor( date1 / 100) + 1 local century2 = math.floor( date2 / 100) + 1 if decade1 == 0 and date1 < date2 then return "prelom 1. a 2. desaťročia " .. century1 .. ". storočia" elseif decade2 == 0 and date2 < date1 then return "prelom 9. a 10. desaťročia " .. century1 .. ". storočia" elseif (decade1 == 9 and date1 < date2) or (decade2 == 9 and date2 < date1) then return "prelom " .. century1 .. ". a " .. century2 .. ". storočia" else return "prelom " .. decade1 .. "0. a " .. decade2 .. "0. rokov " .. century1 .. ". storočia" end end, sl='pozna $date1-ta in zgodnja $date2-ta leta', uk='кінець $date1-х — початок $date2-х рр.', ur='اخیر دہائی $date1 و ابتدا دہائی $date2', vi='bước sang thập niên $date2', ['zh-hans']='$date1年代末$date2年代初', ['zh-hant']='$date1年代末$date2年代初', default=function(date1, date2, state) return {conj='and', adj1 = 'late', unit1='decade', era1=state.era1, adj2 = 'early', unit2='decade', era2=state.era2} end, }, -- $date1 - original date - 1 -- $date2 - original date -- if era is BC than $date1 and $date2 are swapped ['turn of the year']={ nDates = 2, ['be-tarask']='канец $date1 — пачатак $date2 г.', bn='$date1-এর শেষে এবং $date2-এর শুরুতে', cs='přelom roku $date1/$date2', de='Jahreswechsel $date1/$date2', en='late $date1 and early $date2', ['en-gb']='late $date1 and early $date2', ['en-ca']='late $date1 and early $date2', eo='jarŝanĝo $date1 / $date2', es='finales de $date1 y principios de $date2', fa='اواخر $date1 و اوایل $date2', fi='vuoden $date1 loppu ja vuoden $date2 alku', fr='fin $date1 / début $date2', hsb='kónc $date1/spočatk $date2', ja='$date1年末から$date2年初め', nb='årsskiftet $date1/$date2', nl='eind $date1 en begin $date2', nn='årsskiftet $date1/$date2', pl='koniec $date1 i początek $date2 roku', qu="$date1 qhipaq p'unchawkuna $date2 ñawpaq p'unchawkunapas", ru='конец $date1 — начало $date2 г.', sk='prelom rokov $date1/$date2', sl='konec leta $date1 in začetek $date2', sv='sena $date1 och tidiga $date2', uk='кінець $date1 — початок $date2 р.', ur='اخیر $date1 و ابتدا $date2', vi='bước sang năm $date2', ['zh-hans']='$date1年末$date2年初', ['zh-hant']='$date1年末$date2年初', default=function(date1, date2, state) return {conj='and', adj1 = 'late', unit1='year', era1=state.era1, adj2 = 'early', unit2='year', era2=state.era2} end, }, ['circa2'] = { nDates = 2, ar='حوالي $date1 – $date2', ['be-tarask']={'прыкладна з $date1 да прыкладна $date2', case={'gen','gen'}}, bn='প্রায় $date1 এবং প্রায় $date2-এর মাঝামাঝি', ca='cap a $date1 o $date2', cs='cca $date1 až $date2', da='ca. mellem $date1 og $date2', de='etwa $date1 bis $date2', el='περίπου μεταξύ $date1 και $date2', en='between circa $date1 and circa $date2', ['en-gb']='between circa $date1 and circa $date2', ['en-ca']='between circa $date1 and circa $date2', eo='proksimume de $date1 ĝis $date2', es='hacia $date1 o $date2', et='ca. $date1 ja $date2 vahel', fa='حدوداً بین $date1 و $date2', fi={function(date1, date2, state) return 'suunnilleen ' .. decYear(state,'fi','xxx') .. '$date1 ja $date2 välisenä aikana' end, case={'gen','gen'}}, fr='vers $date1-$date2', gl='entre $date1 e $date2', he='בסביבות ה- $date1 עד $date2', hr='oko između $date1 i $date2', hsb={'wot něhdźe $date1 do něhdźe $date2', case={'gen','gen'}}, hu='$date1 és $date2 között', it='tra il $date1 e il $date2 circa', ja='$date1頃と$date2頃の間', mk='~ помеѓу $date1 и $date2', nb='ca. mellom $date1 og $date2', nn='ca. mellom $date1 og $date2', nds='üm un bi $date1 bet $date2', nl='ca. $date1 tot $date2', no='ca. mellom $date1 og $date2', pl={'od około $date1 do około $date2', case={'gen','gen'}}, pt='cerca de $date1 a $date2', qu="$date1 p'unchawmantachá $date2 p'unchawkamachá", ro='circa $date1 – $date2', ru={'с около $date1 до, примерно, $date2', case={'gen','gen'}}, sk='cca $date1 až $date2', sl={function(date1, date2, state) return 'ok. ' .. decYear(state,'sl','gen') .. ' $date1 do $date2' end, case={'gen','gen'}}, sv='c:a $date1 till $date2', uk={'з близько $date1 до, приблизно, $date2', case={'gen','gen'}}, ur='قریباً بین $date1 و $date2', vi='giữa vào khoảng $date1 và vào khoảng $date2', ['zh-hans']='约$date1~$date2间', ['zh-hant']='約$date1~$date2間', default=function(date1, date2, state) return {conj='between', adj1 = 'circa', unit1=state.unit1, era1=state.era1, adj2 = 'circa', unit2=state.unit2, era2=state.era2} end, }, -- ========================================== -- === Eras and calendars =================== -- ========================================== ['julian'] = { nDates = 2, ar='$date1 ($date2 حسب [[w:ar:التقويم اليولياني|تقويم يولياني]])', ['be-tarask']='$date1 ($date2 паводле [[w:be-tarask:Юліянскі каляндар|ст. ст.]]', bn='$date1 (জুলিয়ান ক্যালেন্ডারে $date2)', ca='$date1 ($date2 segons el [[w:ca:Calendari julià|calendari julià]])', cs='$date1 ($date2 podle [[w:cs:Juliánský kalendář|juliánského kalendáře]])', da='$date1 ($date2 [[w:da:Julianske kalender|Julianske kalender]])', de='$date1 ($date2 [[w:de:Julianischer Kalender|Julianischer Kalender]])', el='$date1 ($date2 με το [[w:el:Ιουλιανό ημερολόγιο|Ιουλιανό ημερολόγιο]])', en='$date1 ($date2 in [[w:Old Style and New Style dates|Julian calendar]])', ['en-gb']='$date1 ($date2 in [[w:Old Style and New Style dates|Julian calendar]])', ['en-ca']='$date1 ($date2 in [[w:Old Style and New Style dates|Julian calendar]])', fa='$date1 ($date2 در [[w:fa:Old Style and New Style dates|تقویم جولیان]])', eo='$date1 ($date2 laŭ la [[w:eo:Julia kalendaro|Julia Kalendaro]])', es='$date1 ($date2 según el [[w:es:Calendario juliano|calendario juliano]])', et='$date1 ($date2 [[w:et:Juliuse kalender|Juliuse kalendris]])', fi='$date1 ($date2 [[w:fi:juliaaninen kalenteri|juliaanisen kalenterin]] mukaan)', fr='$date1 ($date2 dans le [[w:fr:calendrier julien|calendrier julien]])', gl='$date1 ($date2 segundo o [[w:gl:Calendario xuliano|calendario xuliano]])', hu='$date1 ($date2 a [[w:hu:Julianus-naptár|Julián naptárban]])', hr='$date1 ($date2 prema [[w:hr:Julijanski kalendar|julijanskom kalendaru]])', he='$date1 ($date2 ב[[w:he:לוח היוליאני|הלוח היוליאני]])', hsb='$date1 ($date2 po julianiskej protyce)', it='$date1 ($date2 secondo il [[w:it:Calendario giuliano|calendario giuliano]])', ja='$date1([[w:ja:ユリウス暦|ユリウス暦]] $date2)', mk='$date1 ($date2 по [[w:mk:Јулијански календар|Јулијанскиот календар]])', ml='$date1 ([[w:Old Style and New Style dates|ജൂലിയൻ കാലഗണനാരീതിയിൽ]] $date2)', nds='$date1 ($date2 na’n [[w:nds:Juliaansch Klenner|Juliaanschen Klenner]])', nb='$date1 ($date2 etter [[w:no:Juliansk kalender|den julianske kalenderen]])', nn='$date1 ($date2 etter [[w:no:Juliansk kalender|den julianske kalenderen]])', nl='$date1 ($date2 volgens de [[w:nl:Juliaanse kalender|Juliaanse kalender]])', no='$date1 ($date2 etter [[w:no:Juliansk kalender|den julianske kalender]])', pl='$date1 ($date2 wedle [[w:pl:Daty nowego i starego porządku|kalendarza juliańskiego]])', pt='$date1 ($date2 no [[w:pt:Mudança para o calendário gregoriano|calendário juliano]])', qu='$date1 ($date2 [[w:qu:Hulyanu kalindaryu|Hulyanu kalindaryupi]])', ro='$date1 ($date2 în [[w:ro:calendarul iulian|calendarul iulian]])', ru='$date1 ($date2 [[w:ru:Юлианский календарь|по ст. ст.]])', sk='$date1 ($date2 podľa [[w:sk:Juliánsky kalendár|juliánskeho kalendára]])', sl='$date1 ($date2 po [[w:sl:Julijanski koledar|julijanskem koledarju]])', sv='$date1 ($date2 [[w:sv:Gamla stilen|gamla stilen]])', uk='$date1 ($date2 [[w:uk:Юліанський календар|Юліанський календар]])', ur='$date1 ($date2 حسب [[w:ur:نئے اور پانے انداز کی تاریخ|جولین تقویم]])', vi='$date1 ($date2 trong [[w:vi:Lịch Julius|lịch Juliêng]])', ['zh-hans']='$date1([[w:Old Style and New Style dates|格里历]]$date2)', ['zh-hant']='$date1([[w:Old Style and New Style dates|格里曆]]$date2)', default='<span style="color:red">$date1 ($date2 in [[w:Old Style and New Style dates|Julian calendar]])</span>', }, ['ad'] = { nDates = 1, ['be-tarask']='$date1 [[w:be-tarask:ад Нараджэньня Хрыста|пасьля Н. Х.]]', bn ='$date1 খ্রিস্টাব্দ', ca ='$date1 dC', cs ='$date1 n. l.', de ='$date1 n. Chr.', el ='$date1 μ.Χ.', en ='$date1 [[w:en:Anno Domini|AD]]', ['en-gb'] ='$date1 [[w:en:Anno Domini|AD]]', ['en-ca'] ='$date1 [[w:en:Anno Domini|AD]]', eo ='$date1 pK', es ='$date1 [[w:es:Anno Dómini|d. C.]]', fa ='$date1 م.', fi ='$date1 jaa.', fr ='$date1 ap. J.-C.', gl ='$date1 d.C.', he ='$date1 לספירה', hu ='i. sz. $date1', hr ='$date1 p. Kr.', hsb='$date1 po Chr.', it ='$date1 d.C.', ja ='西暦$date1', mk ='$date1 н.е.', ml ='ക്രി.വ. $date1', nb ='$date1 e.Kr.', nl ='$date1 n.Chr.', nn ='$date1 e.Kr.', no ='$date1 e.Kr.', pl ='$date1 [[w:pl:naszej ery|n.e.]]', ro ='$date1 d.Hr.', ru ='$date1 н. э.', sk ='$date1 po Kr.', sl ='$date1 n. št.', sv ='$date1 [[w:sv:Efter Kristus|e.Kr.]]', uk ='$date1 н. е.', ur ='$date1 ء', vi ='$date1 [[w:vi:Công Nguyên|CN]]', ['zh-hans'] ='[[w:zh:基督纪年|公元]]$date1', ['zh-hant'] ='[[w:zh:基督纪年|公元]]$date1', default='<span style="color:red">$date1 [[w:en:Anno Domini|AD]]</span>', }, ['ah'] = { nDates = 1, ['be-tarask']='$date1 [[w:be-tarask:Ісламскі каляндар|хіджры]]', bn ='$date1 [[w:bn:ইসলামি বর্ষপঞ্জি|হিজরী]]', cs ='$date1 [[w:cs:Anno Hegirae|AH]]', en ='$date1 [[w:en:Hijri year|AH]]', ['en-gb'] ='$date1 [[w:en:Hijri year|AH]]', ['en-ca'] ='$date1 [[w:en:Hijri year|AH]]', eo ='$date1 post la [[w:eo:Heĝiro|Heĝiro]]', fa ='$date1 ه.ق.', fr ='$date1 [[w:fr:Calendrier musulman|A.H.]]', he ="$date1 [[w:he:הלוח המוסלמי|להג'רה]]", hr ='$date1 god. hidžre', ja ='[[w:ja:ヒジュラ暦|ヒジュラ暦]]$date1', nb ='$date1 [[w:no:Den muslimske kalenderen|A.H.]]', nn ='$date1 [[w:nn:Den muslimske kalenderen|A.H.]]', pl ='$date1 [[w:pl:Kalendarz muzułmański|A.H.]]', ru ='$date1 [[w:ru:Исламский календарь|хиджры]]', sk ='$date1 [[w:sk:A. H.|A. H.]]', sv ='$date1 [[w:sv:Muslimska kalendern|A.H.]]', uk ='$date1 [[w:uk:Мусульманський календар|хіджри]]', ur ='$date1 ھ', vi ='$date1 [[w:vi:Lịch Hồi giáo|AH]]', ['zh-hans'] ='[[w:en:Hijri year|Hijri历]]$date1', ['zh-hant'] ='[[w:en:Hijri year|Hijri曆]]$date1', default='<span style="color:red">$date1 [[w:en:Hijri year|AH]]</span>', }, ['bc'] = { nDates = 1, ar ='$date1 ق.م.', ['be-tarask']='$date1 [[w:be-tarask:да Нараджэньня Хрыста|да Н. Х.]]', bn ='খ্রিস্টপূর্ব $date1', ca ='$date1 [[w:ca:Abans de Crist|aC]]', cs ='$date1 [[w:cs:Př. n. l.|př. n. l.]]', de ='$date1 [[w:de:v. Chr.|v. Chr.]]', el ='$date1 π.Χ.', en ='$date1 [[w:en:Ante Christum Natum|BC]]', ['en-gb'] ='$date1 [[w:en:Ante Christum Natum|BC]]', ['en-ca'] ='$date1 [[w:en:Ante Christum Natum|BC]]', eo ='$date1 aK', es ='$date1 [[w:es:Antes de Cristo|a. C.]]', fa ='$date1 پ.م.', fi ='$date1 eaa.', fr ='$date1 av. J.-C.', gl ='$date1 [[w:gl:Antes de Cristo|a.C.]]', he ='$date1 לפני הספירה', hr ='$date1 [[w:hr:Pr. Kr.|pr. Kr.]]', hsb='$date1 do Chr.', hu ='i. e. $date1', it ='$date1 [[w:it:Avanti Cristo|a.C.]]', ja ='[[w:ja:紀元前|紀元前]]$date1', mk ='$date1 п.н.е.', ml ='ക്രി.മു. $date1', nds='$date1 vör uns Tied', nb ='$date1 f.Kr.', nl ='$date1 v.Chr.', nn ='$date1 f.Kr.', no ='$date1 f.Kr.', pl ='$date1 [[w:pl:przed naszą erą|p.n.e.]]', ro ='$date1 î.Hr.', ru ='$date1 до н. э.', sk ='$date1 [[w:sk:Pred Kristom|pred Kr.]]', sl ='$date1 pr. n. št.', sv ='$date1 [[w:sv:Före Kristus|f.Kr.]]', uk ='$date1 до н. е.', ur ='$date1 ق م', vi ='$date1 [[w:vi:Trước Công Nguyên|TCN]]', ['zh-hans'] ='[[w:zh:基督纪年|公元前]]$date1', ['zh-hant'] ='[[w:zh:基督纪年|公元前]]$date1', default='<span style="color:red">$date1 [[w:en:Ante Christum Natum|BC]]</span>', }, ['bp'] = { nDates = 1, ar ='$date1 [[w:ar:قبل الحاضر|قبل الحاضر]]', be ='$date1 [[w:be-tarask:Да нашых дзён|Да нашых дзён]]', ['be-tarask']='$date1 [[w:be-tarask:Да нашых дзён|Да нашых дзён]]', bn ='বর্তমানের আগে $date1', ca ='$date1 [[w:ca:BP (unitat de temps)|BP]]', cs ='$date1 [[w:cs:B. P.|B. P.]]', de ='$date1 [[w:de:Before Present|BP]]', el ='$date1 [[w:en:Before Present|BP]]', en ='$date1 [[w:en:Before Present|BP]]', ['en-gb'] ='$date1 [[w:en:Before Present|BP]]', ['en-ca'] ='$date1 [[w:en:Before Present|BP]]', eo='$date1 [[w:eo:Before Present|BP]]', es ='$date1 [[w:es:Before Present|BP]]', et ='$date1 [[w:et:Before Present|BP]]', fa ='$date1 پیش از اکنون', fi ='$date1 [[w:fi:BP (ajanlasku)|BP]]', fr ='$date1 [[w:fr:Avant le présent|avant le présent]]', hr ='$date1 [[w:hr:BP|prije današnjice]]', it ='$date1 [[w:it:Before Present|BP]]', ja ='$date1 [[w:ja:BP (年代測定)|BP]]', lv ='$date1 [[w:lv:Pirms mūsdienām|Pirms mūsdienām]]', mk ='$date1 [[w:mk:Пред сегашноста|п.с.]]', ml ='[[w:en:Before Present|ഇന്നത്തെ കാലത്തിനു മുമ്പ്]] $date1', nb ='$date1 [[w:no:Before Present|BP]]', nn ='$date1 [[w:nn:Before Present|BP]]', nl ='$date1 [[w:nl:Before Present|BP]]', no ='$date1 [[w:no:Before Present|BP]]', pl ='$date1 [[w:pl:Before Present|BP]]', pt ='$date1 [[w:pt:Antes do Presente|Antes do Presente]]', ru ='$date1 [[w:ru:До настоящего времени|до н. в.]]', sk ='$date1 [[w:sk:BP (čas)|BP]]', sl ='$date1 [[w:sl:pred sedanjostjo|p. s.]]', sr ='$date1 [[w:sr:Прије садашњости|Прије садашњости]]', sv ='$date1 [[w:sv:B.P.|B.P.]]', uk ='$date1 [[w:uk:Років тому|Років тому]]', ur ='$date1 قبل حاضر', vi ='$date1 [[w:en:Before Present|trước ngày nay]]', ['zh-hans'] ='[[w:zh:距今|距今]]$date1', ['zh-hant'] ='[[w:zh:距今|距今]]$date1', default='<span style="color:red">$date1 [[w:en:Before Present|BP]]</span>', }, } -- List of possible string inputs to "adj", "junction", "era", and "precision" fields -- Each term is matched to its synonym and the role: a - adjective, e - era -- p - precision, c - calendar and combos, r - certainty and j - conjunction p.Synonyms = { -- adjectives and prepositions ['quarter1']={'1quarter','a'}, ['1stquarter']={'1quarter','a'}, ['1st quarter']={'1quarter','a'}, ['first quarter']={'1quarter','a'}, ['1quarter']={'1quarter','a'}, ['quarter2']={'2quarter','a'}, ['2ndquarter']={'2quarter','a'}, ['2nd quarter']={'2quarter','a'}, ['second quarter']={'2quarter','a'}, ['2quarter']={'2quarter','a'}, ['quarter3']={'3quarter','a'}, ['3rdquarter']={'3quarter','a'}, ['3rd quarter']={'3quarter','a'}, ['third quarter']={'3quarter','a'}, ['3quarter']={'3quarter','a'}, ['quarter4']={'4quarter','a'}, ['4thquarter']={'4quarter','a'}, ['4th quarter']={'4quarter','a'}, ['fourth quarter']={'4quarter','a'}, ['4quarter']={'4quarter','a'}, ['spring']={'spring','a'}, ['summer']={'summer','a'}, ['fall']={'autumn','a'}, ['autumn']={'autumn','a'}, ['winter']={'winter','a'}, ['beginning']={'early','a'}, ['early']={'early','a'}, ['1half']={'firsthalf','a'}, ['1sthalf']={'firsthalf','a'}, ['1st half']={'firsthalf','a'}, ['firsthalf']={'firsthalf','a'}, ['first half']={'firsthalf','a'}, ['end']={'late','a'}, ['late']={'late','a'}, ['middle']={'mid','a'}, ['mid']={'mid','a'}, ['2half']={'secondhalf','a'}, ['2ndhalf']={'secondhalf','a'}, ['2nd half']={'secondhalf','a'}, ['secondhalf']={'secondhalf','a'}, ['second half']={'secondhalf','a'}, ['<']={'before','a'}, ['b']={'before','a'}, ['before']={'before','a'}, ['>']={'after','a'}, ['a']={'after','a'}, ['after']={'after','a'}, ['~']={'circa','a'}, ['c']={'circa','a'}, ['ca']={'circa','a'}, ['circa']={'circa','a'}, ['by']={'by','a'}, ['from']={'from','a'}, ['until']={'until','a'}, ['uncertain']={'uncertain','r'}, ['possibly']={'possibly','r'}, ['probably']={'probably','r'}, ['presumably']={'presumably','r'}, -- eras ['bc']={'bc','e'}, ['bce']={'bc','e'}, ['before present']={'bp','e'}, ['bp']={'bp','e'}, ['ce']={'ad','e'}, ['ad']={'ad','e'}, ['ah']={'ah','e'}, -- conjunctions ['&']={'and','j'}, ['and']={'and','j'}, ['or']={'or','j'}, ['-']={'from-until','j'}, ['–']={'from-until','j'}, ['from-until']={'from-until','j'}, ['between']={'between','j'}, ['circa2']={'circa2','a'}, -- precision ['day']={'day','p'}, ['month']={'month','p'}, ['year']={'year','p'}, ['s']={'decade','p'}, ['decade']={'decade','p'}, ['century']={'century','p'}, ['millennium']={'millennium','p'}, ['million']={'million','p'}, ['billion']={'billion','p'}, -- calendar ['julian']={'julian','c'}, ['islamic']={'islamic','c'}, ['hijri']={'islamic','c'}, -- "Turn of the ..." options are a combos which will be handled in similar way as calendars ['turn of the century']={'turn of the century','c'}, ['century turn']={'turn of the century','c'}, ['turn of the decade']={'turn of the decade','c'}, ['decade turn']={'turn of the decade','c'}, ['turn of the year']={'turn of the year','c'}, ['year turn']={'turn of the year','c'}, -- other dates which will be handled in similar way as calendars ['?']={'unknown','c'}, ['unknown']={'unknown','c'}, ['unknown year']={'year unknown','c'}, ['year unknown']={'year unknown','c'}, } return p q6ui71e4rd3u1w90oi1m7a7oa51ow6o 模块:ISOdate 828 14849 43055 2026-07-07T17:55:13Z 内存溢出的猫 7954 From [[zh:Module:ISOdate]] 43055 Scribunto text/plain --[[ This module is intended for processing of date strings. Please do not modify this code without applying the changes first at Module:ISOdate/sandbox and testing at Module:ISOdate/sandbox/testcases and Module talk:ISOdate/sandbox/testcases. Authors and maintainers: * User:Parent5446 - original version of the function mimicking template:ISOdate * User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear ]] local p = {} -- ======================================= -- === Dependencies ====================== -- ======================================= local D = require('Module:DateI18n') -- the enwp version of c:Module:Date --[[ ISOyear This function returns year part of date string. Usage: {{#invoke:ISOdate|ISOyear|target_string}} Parameters 1: The date string Error Handling: If the string does not look like it contain the year than the function will not return anything. That is the preferred treatment for the template:Creator which is the main (only?) template calling it. ]] function p.ISOyear( frame ) return p._ISOyear( frame.args[1] ) end function p._ISOyear( input ) if not input then return '' end input = mw.text.trim( input ) -- if empty string then return it if input == "" then return input end -- if number then return it if tonumber( input ) then return mw.ustring.format( '%04i', input ) end -- otherwise use regular expression match input = mw.ustring.match( input, '^+?(-?%d%d?%d?%d?)-' ) if input and tonumber( input ) then return mw.ustring.format( '%04i', input ) else return '' end end --[[ ISOdate This function is the core part of the ISOdate template. Usage: {{#invoke:ISOdate|ISOdate|target_string|lang=}} Parameters: 1: The date string lang: The language to display it in form: Language format (genitive, etc.) for some languages class: CSS class for the <time> node Error Handling: If the string does not look like it contain the proper ISO date than the function will return the original string. That is the preferred treatment for the template:Information (and similar templates) which calling it. ]] function p.ISOdate(frame) local datestr, succeded local args = frame.args if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language end datestr, succeded = p._ISOdate( mw.text.trim(args[1]), args.lang, -- language args.case or '', -- allows to specify grammatical case for the month for languages that use them args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is ) return datestr end function p._ISOdate(datestr, lang, case, class, trim_year) -- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any -- regexp hints: -- 1) Strings starting with "^" and ending with "$" indicate whole string match -- 2) optional tail part copied as-is and following the main parsed part of the date have to be separated from the date by a whitespace, so "(\s.+)?" local patterns = { -- strings starting with YYYY-MM-DD HH:MM:SS. Year 4 digits (if we know seconds than it was within the last 100 years), the rest 1-2 -- date and time can be separated by space or "T" and there could be a "Z" on the end indicating "Zulu" time zone {dlen=6, tail=7, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?):(%d%d?)Z?(%s.*)"}, {dlen=6, tail=0, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?):(%d%d?)Z?$"}, -- strings starting with YYYY-MM-DD HH:MM. Year 4 digits, the rest 1-2 -- (if one knows hour and minute than it was probably after a year 1000) {dlen=5, tail=6, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?)(%s.+)"}, {dlen=5, tail=0, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?)$"}, -- strings starting with YYYY-MM-DD. Year 1-4 digits, the rest 1-2 {dlen=3, tail=4, regexp="^+?(%d%d?%d?%d?)-(%d%d?)-(%d%d?)(%s.+)"}, {dlen=3, tail=0, regexp="^+?(%d%d?%d?%d?)-(%d%d?)-(%d%d?)$"}, -- strings starting with YYYY-MM. Year 3-4 digits, month 2 digits -- (want to avoit converting to dates strings like 10-5 = 5 {dlen=2, tail=3, regexp="^+?(%d%d%d%d?)-(%d%d)(%s.+)"}, -- if whole string is in YYYY-MM form: If Year 1-4 digits, month 1-2 digits {dlen=2, tail=0, regexp="^+?(%d%d?%d?%d?)-(%d%d?)$"}, -- string starts with a number -> it has to be 3 or 4 digit long to be a year {dlen=1, tail=2, regexp="^+?(%d%d%d%d?)(%s.+)"}, -- if whole string is a number (1-4 digit long) than it will be interpreted as a year {dlen=1, tail=0, regexp="^+?(%d%d?%d?%d?)$"}, } -- create datevec based on which variables are provided local datevec, tail, formatNum datevec, tail, formatNum = p.test_date_formats(datestr or '', patterns) if datevec[1]=='' or datevec[1]==nil then -- quickly return if datestr does not look like date (it could be a template) return datestr, false end -- call p._Date function to format date string local succeded, datestr2 succeded, datestr2 = pcall( D._Date, datevec, lang, case, class, trim_year) if succeded and datestr2~='' then return mw.text.trim( datestr2 .. tail), true else -- in case of errors return the original string return datestr, false end end function p.ISOdate_extended(frame) -- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any -- regexp hints: -- 1) Strings starting with "^" and ending with "$" indicate whole string match -- 2) optional tail part copied as-is and following the main parsed part of the date have to be separated from the date by a whitespace, so "(\s.+)?" local datestr, succeded local args = frame.args if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language end datestr, succeded = p._ISOdate( mw.text.trim(args[1]), args.lang, -- language args.case or '', -- allows to specify grammatical case for the month for languages that use them args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is ) if succeded then return datestr end local patterns = { -- Exended set of recognized formats: like MM/DD/YYYY {dlen=3, tail=4, regexp="^(%d%d?)[-./](%d%d?)[-./](%d%d%d%d)(%s.+)"}, {dlen=3, tail=0, regexp="^(%d%d?)[-./](%d%d?)[-./](%d%d%d%d)$"}, {dlen=3, tail=0, regexp="^(%d%d?)%s(%w+)%s(%d%d%d%d)$"}, {dlen=3, tail=0, regexp="^(%w+)%s(%d%d?),%s(%d%d%d%d)$"}, } local datevec, tail, formatNum, category = '' datevec, tail, formatNum = p.test_date_formats(frame.args[1], patterns) if formatNum==1 or formatNum==2 then vec = datevec; if tonumber(datevec[1])>12 then frame.args[1] = string.format('%04i-%02i-%02i', datevec[3], datevec[2], datevec[1] ) category = '[[Category:Date in DD/MM/YYYY format]]' return mw.text.trim( p.ISOdate(frame) .. tail); elseif tonumber(datevec[2])>12 then frame.args[1] = string.format('%04i-%02i-%02i', datevec[3], datevec[1], datevec[2] ) category = '[[Category:Date in MM/DD/YYYY format]]' return mw.text.trim( p.ISOdate(frame) .. tail); end elseif (formatNum==3 or formatNum==4) and (datevec[3]=='' or datevec[3]~=nil) then local str = mw.getCurrentFrame():callParserFunction( "#time", { 'Y-m-d', datestr} ) local vec = {str:match( "^(%d%d?%d?%d?)-(%d%d?)-(%d%d?)$" )} if vec and vec[1]~=nil then frame.args[1] = string.format('%04i-%02i-%02i', vec[1], vec[2], vec[3] ) category = '[[Category:Date in word format]]' return p.ISOdate(frame); end end return datestr end function p.test_date_formats(datestr, patterns) -- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any local datevec = {'','','','','',''} local tail = '' local vec, pat local formatNum = 0 for i, pat in ipairs( patterns ) do vec = {datestr:match( pat.regexp )} if vec and vec[1]~=nil then for j=1,pat.dlen do datevec[j] = vec[j] end if pat.tail>0 and vec[pat.tail]~=nil then tail = mw.ustring.gsub(' ' .. vec[pat.tail], ' +', ' ') end formatNum = i break end end return datevec, tail, formatNum end return p nab04kxj0ywahk6drgfjdo6jbixhup7 模块:Calendar 828 14850 43056 2026-07-07T17:55:17Z 内存溢出的猫 7954 From [[zh:Module:Calendar]] 43056 Scribunto text/plain -- This module renders the calendar seen on [[Portal:Current events]]. local p = {} local function makeWikilink(link, display) if display then return string.format('[[%s|%s]]', link, display) else return string.format('[[%s]]', link) end end function p.main() local dateStuff = p.getDateStuff() local dayStrings = p.makeDayStrings(dateStuff) return p.export(dayStrings, dateStuff) end function p.getDateStuff() -- Gets date data. local dateStuff = {} local lang = mw.language.getContentLanguage() --Year local year = lang:formatDate('Y') year = tonumber(year) dateStuff.year = year -- Month local month = lang:formatDate('F') dateStuff.month = month -- Month and year local monthAndYear = lang:formatDate('F Y') local firstOfMonth = lang:formatDate('01-m-Y') dateStuff.monthAndYear = monthAndYear -- Previous month and year dateStuff.previousMonthAndYear = lang:formatDate('F Y', firstOfMonth .. ' -1 month') -- Next month and year dateStuff.nextMonthAndYear = lang:formatDate('F Y', firstOfMonth .. ' +1 month') -- Day local day = lang:formatDate('j') day = tonumber(day) dateStuff.day = day -- Days in month local daysInMonth = lang:formatDate('j', firstOfMonth .. ' +1 month -1 day') daysInMonth = tonumber(daysInMonth) dateStuff.daysInMonth = daysInMonth -- Weekday of the first day of the month local firstWeekday = lang:formatDate('w', firstOfMonth) -- Sunday = 0, Saturday = 6 firstWeekday = tonumber(firstWeekday) firstWeekday = firstWeekday + 1 -- Make compatible with Lua tables. Sunday = 1, Saturday = 7. dateStuff.firstWeekday = firstWeekday return dateStuff end function p.makeDayStrings(dateStuff) local calStrings = {} local currentDay = dateStuff.day local isLinkworthy = p.isLinkworthy local currentMonth = dateStuff.month local currentYear = dateStuff.year local makeDayLink = p.makeDayLink for day = 1, dateStuff.daysInMonth do if isLinkworthy(day, currentDay) then calStrings[#calStrings + 1] = makeDayLink(day, currentMonth, currentYear) else calStrings[#calStrings + 1] = tostring(day) end end return calStrings end function p.isLinkworthy(day, currentDay) -- Returns true if the calendar day should be linked, and false if not. -- Days should be linked if they are the current day or if they are within the six -- preceding days, as that is the number of items on the current events page. if currentDay - 6 <= day and day <= currentDay then return true else return false end end function p.makeDayLink(day, month, year) return string.format("'''[[#%d %s %d|&nbsp;&nbsp;%d&nbsp;&nbsp;]]'''", year, month, day, day) end function p.export(dayStrings, dateStuff) -- Generates the calendar HTML. local monthAndYear = dateStuff.monthAndYear local root = mw.html.create('table') root :addClass('infobox') :css{ display = 'table', width = '100%', float = 'initial', ['max-width'] = '350px', margin = 'auto !important', ['text-align'] = 'center', ['background-color'] = '#f5faff', border = '1px solid #cedff2' } -- Headings :tag('tr') :css('background-color', '#cedff2') :tag('th') :css{['text-align'] = 'center'} :wikitext(makeWikilink('Portal:Current events/' .. dateStuff.previousMonthAndYear, '◀')) :done() :tag('th') :attr('colspan', '5') :css{['text-align'] = 'center'} :wikitext(makeWikilink('Portal:Current events/' .. monthAndYear, monthAndYear)) :done() :tag('th') :css{['text-align'] = 'center'} :wikitext(makeWikilink('Portal:Current events/' .. dateStuff.nextMonthAndYear, '▶')) -- Day of week headings local dayHeadingRow = root:tag('tr') local weekdays = {'S', 'M', 'T', 'W', 'T', 'F', 'S'} for i, weekday in ipairs(weekdays) do dayHeadingRow:tag('th') :css{['width'] = '14%', ['text-align'] = 'center'} :wikitext(weekday) end -- Days local colspan = dateStuff.firstWeekday - 1 local cellCount = 0 -- Tracks the number of day cells. local firstDayRow = root:tag('tr') if colspan > 1 then firstDayRow:tag('td') :attr('colspan', tostring(colspan)) elseif colspan == 1 then firstDayRow:tag('td') end for i = colspan + 1, 7 do -- Finish the first row cellCount = cellCount + 1 firstDayRow:tag('td') :css{['text-align'] = 'center'} :wikitext(dayStrings[cellCount]) end while cellCount < #dayStrings do -- Second day row onwards local otherDayRow = root:tag('tr') for i = 1, 7 do cellCount = cellCount + 1 local dayString = dayStrings[cellCount] if not dayString then dayString = " " end otherDayRow:tag('td') :css{['text-align'] = 'center'} :wikitext(dayString) end end -- Footer root:tag('tr') :tag('td') :attr('colspan', '7') :css{['padding-top'] = '3px', ['padding-bottom'] = '5px', ['font-size'] = '78%', ['text-align'] = 'right'} :wikitext('&nbsp;&nbsp; ' .. makeWikilink('Portal:Current events/' .. monthAndYear, 'More ' .. monthAndYear .. ' events... &nbsp;&nbsp;')) return tostring(root) end return p dkg5em989dfopn43g89mdcuxes6hfmo 模块:Ordinal 828 14851 43057 2026-07-07T17:55:19Z 内存溢出的猫 7954 From [[zh:Module:Ordinal]] 43057 Scribunto text/plain --[[ This template will add the appropriate ordinal suffix to a given integer. Please do not modify this code without applying the changes first at Module:Ordinal/sandbox and testing at Module:Ordinal/sandbox/testcases and Module talk:Ordinal/sandbox/testcases. ]] local p = {} local yesno = require('Module:Yesno') -- boolean value interpretation --[[ This function converts an integer value into a numeral followed by ordinal indicator. The output string might contain HTML tags. Usage: {{#invoke:Ordinal|ordinal|1=|2=|sup=}} {{#invoke:Ordinal|ordinal}} - uses the caller's parameters Parameters 1: Any number or string. 2: Set to "d" if the module should display "d" instead of "nd" and "rd". sup: Set to yes/no to toggle superscript ordinal suffix. ]] function p.ordinal(frame) local args = frame.args if args[1] == nil then args = frame:getParent().args end if args[1] == nil then args[1] = "{{{1}}}" end return p._ordinal(args[1], (args[2] == 'd'), yesno(args.sup)) end function p._ordinal(n, d, sup) local x = tonumber(mw.ustring.match(n, "(%d*)%W*$")) local suffix = "th" -- If tonumber(n) worked: if x then local mod10 = math.abs(x) % 10 local mod100 = math.abs(x) % 100 if mod10 == 1 and mod100 ~= 11 then suffix = "st" elseif mod10 == 2 and mod100 ~= 12 then if d then suffix = "d" else suffix = "nd" end elseif mod10 == 3 and mod100 ~= 13 then if d then suffix = "d" else suffix = "rd" end end end if sup then suffix = "<sup>" .. suffix .. "</sup>" end return n .. suffix end return p mfvnnawmnoleno9ajd0ky9qh5dif9rm 模块:Roman 828 14852 43058 2026-07-07T17:55:21Z 内存溢出的猫 7954 From [[zh:Module:Roman]] 43058 Scribunto text/plain -- This module implements {{Roman}}. local p = {} -- This function implements the {{overline}} template. local function overline(s) return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s ) end -- Gets the Roman numerals for a given numeral table. Returns both the string of -- numerals and the value of the number after it is finished being processed. local function getLetters(num, t) local ret = {} for _, v in ipairs(t) do local val, letter = unpack(v) while num >= val do num = num - val table.insert(ret, letter) end end return table.concat(ret), num end -- The main control flow of the module. local function _main(args) -- Get input and exit displaying nothing if the input is empty. if args[1] == nil then return end local num = tonumber(args[1]) if not num or num < 0 or num == math.huge then error('无效数字' .. args[1], 2) elseif num == 0 then return 'N' end -- Return a message for numbers too big to be expressed in Roman numerals. if num >= 5000000 then return args[2] or 'N/A' end local ret = '' -- Find the Roman numerals for the large part of numbers. -- 23 April 2016 - tweaked to >= 4000 to accept big Roman 'IV' -- The if statement is not strictly necessary, but makes the algorithm -- more efficient for smaller numbers. if num >= 4000 then local bigRomans = { { 1000000, 'M' }, { 900000, 'CM' }, { 500000, 'D' }, { 400000, 'CD' }, { 100000, 'C' }, { 90000, 'XC' }, { 50000, 'L' }, { 40000, 'XL' }, { 10000, 'X' }, { 9000, 'IX' }, { 5000, 'V' }, { 4000, 'IV' }, } local bigLetters bigLetters, num = getLetters(num, bigRomans) ret = overline(bigLetters) end -- Find the Roman numerals for numbers less than the big Roman threshold. local smallRomans = { { 1000, 'M' }, { 900, 'CM' }, { 500, 'D' }, { 400, 'CD' }, { 100, 'C' }, { 90, 'XC' }, { 50, 'L' }, { 40, 'XL' }, { 10, 'X' }, { 9, 'IX' }, { 5, 'V' }, { 4, 'IV' }, { 1, 'I' } } local smallLetters = getLetters( num, smallRomans ) ret = ret .. smallLetters if args.fraction == 'yes' then -- Find the Roman numerals for the fractional parts of numbers. -- If num is not a whole number, add half of 1/1728 (the smallest unit) to equate to rounding. -- Ensure we're not less than the smallest unit or larger than 1 - smallest unit -- to avoid getting two "half" symbols or no symbols at all num = num - math.floor(num) if num ~= 0 then num = math.max(1.1/1728, math.min(1727.1/1728, num + 1/3456)) end local fractionalRomans = { { 1/2, 'S' }, { 5/12, "''':'''•''':'''" }, { 1/3, "'''::'''" }, { 1/4, "''':'''•" }, { 1/6, "''':'''" }, { 1/12, '•' }, { 1/24, 'Є' }, { 1/36, 'ƧƧ' }, { 1/48, 'Ɔ' }, { 1/72, 'Ƨ' }, { 1/144, '<s>Ƨ</s>' }, { 1/288, '℈' }, { 1/1728, '»' }, } local fractionalLetters = getLetters(num, fractionalRomans) ret = ret .. fractionalLetters end return ret end --請勿刪除此函數,否則將造成元素週期表都顯示錯誤 function p.getRomam(numinput, failed, fraction) --for [[模块:PeriodicTable]] local number = tonumber(numinput or 0); if number < 0 or numinput == nil then return failed or '' end local nargs = {[1] = number} if failed ~= nil then nargs[2] = failed end if fraction ~= nil then nargs.fraction = fraction end return _main(nargs); end function p.main(frame) -- If called via #invoke, use the args passed into the invoking -- template, or the args passed to #invoke if any exist. Otherwise -- assume args are being passed directly in from the debug console -- or from another Lua module. local origArgs if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args for k, v in pairs(frame.args) do origArgs = frame.args break end else origArgs = frame end -- Trim whitespace and remove blank arguments. local args = {} for k, v in pairs(origArgs) do if type( v ) == 'string' then v = mw.text.trim(v) end if v ~= '' then args[k] = v end end -- exit if not given anything if args == nil or args == {} then return end -- Given mathematical expression, simplify to a number if type(args[1]) == 'string' then args[1] = mw.ext.ParserFunctions.expr(args[1]) end return _main(args) end return p soq91lm6wyw51uff65kzi7gn63dacww 模块:Linguistic 828 14853 43059 2026-07-07T17:55:24Z 内存溢出的猫 7954 From [[zh:Module:Linguistic]] 43059 Scribunto text/plain -- some simple internationalization that can be called by other modules local p = {} local f = require('Module:Fallback') local i18n = mw.loadData('Module:I18n/linguistic') local function getText(msg, lang) return f._langSwitch(i18n[msg], lang) end local vowels = 'aeiouyąăẵằẳặȃắâẫấầẩậãäǟāáàȁǎảẚåǻḁạǡæǣǽĕȇêễếềểệḙẽḛëēḕéḗèȅěẻẹęȩḝǝĭȋîĩḭïḯīíìȉǐỉịįıŏȏôỗốồổộõṏṍöōṑóṓòȍǒỏọǫǭơỡớờởợøǿŭȗûṷũṻṹṵüǖǘǜǚṳūúùȕǔủůụųưữứừửựŷỹÿȳýỳỷẙỵ' local function wordor(lang) return getText('or_conj', lang) end local function comma(lang) return getText("comma", lang) end function p.fullstop(lang) return getText("full_stop", lang) end function p.colon(lang) getText("colon", lang) end local function wordand(lang) return getText("and_conj", lang) end local function wordsep(lang) -- default separator between words return getText("word_separator", lang) end local function isin(str, pattern) if str and pattern and mw.ustring.find(str, pattern, 1, true ) then return true end end local function langisin(str, lang) return isin(str, lang .. ' ') -- space is necessary to avoid false positives like zh in zh-hans end local function processgender(str) local t = { f = 'feminine', fem = 'feminine', feminine = 'feminine', n = 'neutral', neutral = 'neutral', m = 'masculine', masc = 'masculine', masculine = 'masculine', } return t[str] or 'masculine' end local function processnumber(str) if (str == 'p') or (str == 'plural') then return 'plural' else return 'singular' end end function p.vowelfirst (str) if str then return isin(vowels, str[1]) end end function p.inparentheses(str, lang) --todo: define language with exotic parentheses if str == '' then return str else return ' (' .. str .. ')' -- needs internationalization. --Needs leading space in Enlgish because as some languages do not use it, it is part of the formatting end end function p.of(word, lang, raw, gender, number, determiner) -- rough translation of "of" in various languages -- note that the cases when on "of" is employed varies a lot among languages, so it is more prudent to call this from lang specific function only if not raw then raw = word end gender = processgender(gender) number = processnumber(number) -- raw is the string without the Wikiformatting so that it correctly analyses the string that is [[:fr:Italie|Italie]] -> 'italie' -- any way to automate this ? -- todo: ca to replace Template:Of/ca if lang == 'fr' then if number == 'plural' then return 'des ' .. word elseif p.vowelfirst(raw) then return 'de l\'' .. word elseif gender == 'feminine' then return 'de la ' .. word elseif derterminer then return 'du ' .. word else return 'de ' .. word end end end function p.noungroup(noun, adj, lang) if not noun or noun == '' then return nil -- not '' so that it is not counted as a string by mw.listToText end if not adj or adj == '' then return noun end -- adjective before the noun if langisin('cs de de-at de-ch en en-ca en-gb pl sk zh zh-cn zh-hans zh-hant zh-my zh-sg zh-tw ', lang) then return adj .. wordsep(lang) .. noun -- adjective after the noun elseif langisin('fr fr-ca es it') then return noun .. wordsep(lang) .. adj else return noun ' (' .. adj .. ')' end end function p.conj(args, lang, conjtype) if (not args) then return nil end local newargs = {} for i, j in pairs(args) do if type(j) ~= 'nil' then table.insert(newargs, j) end end args = newargs if #args == 0 then return nil end if conjtype == 'comma' then return mw.text.listToText(args, comma(lang), comma(lang)) elseif conjtype == 'or' then return mw.text.listToText(args, comma(lang), wordor(lang) .. wordsep(lang)) elseif conjtype == 'explicit or' then -- adds "or" betwen all words when the context can be confusing return mw.text.listToText(args, wordor(lang) .. wordsep(lang), wordor(lang) .. wordsep(lang)) elseif conjtype then return mw.text.listToText(args, conjtype, conjtype) else return mw.text.listToText(args, comma(lang), wordand(lang) .. wordsep(lang)) end end return p t6da3tbyibue9xt7nadyme6ph7qjz64 模块:DateI18n 828 14854 43060 2026-07-07T17:55:28Z 内存溢出的猫 7954 From [[zh:Module:DateI18n]] 43060 Scribunto text/plain --[[ This module is intended for processing of date strings. Copied from https://commons.wikimedia.org/w/index.php?title=Module:Date&oldid=224728211 Used by Module:ISOdate, Module:Complex date, Module:WikidataIB Authors and maintainers: * User:Parent5446 - original version of the function mimicking template:ISOdate * User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear ]] local p = {} -- ======================================= -- === Dependencies ====================== -- ======================================= local i18n = require('Module:I18n/date') -- get localized translations of date formats local yesno = require('Module:Yesno') local function langSwitch(list,lang) local langList = mw.language.getFallbacksFor(lang) table.insert(langList,1,lang) for i,language in ipairs(langList) do if list[language] then return list[language] end end end --[[ Date This function can be used to provide an ISOdate template. Usage: {{#invoke:Date|Date|year=|month=|day=|hour=|minute=|second=|tzhour=|tzmin=|lang=en}} Parameters: year,month,day,hour,minute,second: broken down date-time component strings tzhour, tzmin: timezone offset from UTC, hours and minutes lang: The language to display it in case: Language format (genitive, etc.) for some languages class: CSS class for the <time> node, use "" for no metadata at all Error Handling: ]] function p.Date(frame) local args = frame.args if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language end return p._Date( { args.year or '', args.month or '', args.day or '', args.hour or '', args.minute or '', args.second or '', args.tzhour or '', args.tzmin or '' }, args.lang, -- language args.case or '', -- allows to specify grammatical case for the month for languages that use them args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. This is useful for microformats. args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is ) end function p._Date(datevec, lang, case, class, trim_year) -- make sure inputs are in the right format for i = #datevec + 1, 8 do datevec[i] = '' end if not case then case = '' end if not class then class = '' end if not trim_year then trim_year = '100-999' end -- if language is not provided than look up users language -- WARNING: This step should be done by the template as it does not seem to work as well here (cache issues?) if not lang or not mw.language.isValidCode( lang ) then lang = 'en' end -- Just in case someone broke the internationalization code than fix the english defaults if i18n.DateLang['en'] == nil then i18n.DateLang['en'] = 'en-form' end if i18n.DateFormat['en-form'] == nil then i18n.DateFormat['en-form'] = {YMDHMS='j F Y, H:i:s', YMDHM='j F Y, H:i', YMD='j F Y', YM='F Y', MD='j F', Y='Y'} end -- create datecode based on which variables are provided and check for out of bound values local maxval = {9999, 12, 31, 23, 59, 60, 23, 59} -- max values for year, month, ... local c = {'Y', 'M', 'D', 'H', 'M', 'S', '', ''} local datecode = '' -- a string signifying which combination of variables was provided local datenum = {} -- date-time encoded as a vector = [year, month, ... , second] for i, v in ipairs( datevec ) do if v~=nil and v~='' then datecode = datecode .. c[i] datenum[i] = tonumber(v) if datenum[i]==nil and i==2 then -- month is not a number -> check if it is a month name in English v = mw.language.new('en'):formatDate( "n", v) datenum[i] = tonumber(v) end if datenum[i]==nil or datenum[i]>maxval[i] then -- Some numbers are out of range -> abort and return the empty string return '' end end end -- create time stamp string (for example 2000-02-20 02:20:20) based on which variables were provided local timeStamp if datecode == 'YMDHMS' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5], datenum[6] ) elseif datecode == 'YMDHM' then timeStamp = string.format('%04i-%02i-%02i %02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5] ) elseif datecode:sub(1,3)=='YMD' then timeStamp = string.format('%04i-%02i-%02i', datenum[1], datenum[2], datenum[3] ) datecode = 'YMD' -- 'YMD', 'YMDHMS' and 'YMDHM' are the only supported format starting with 'YMD'. All others will be converted to 'YMD' elseif datecode == 'YM' then timeStamp = string.format('%04i-%02i', datenum[1], datenum[2] ) elseif datecode:sub(1,1)=='Y' then timeStamp = string.format('%04i', datenum[1] ) datecode = 'Y' elseif datecode == 'M' then timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], 1 ) class = '' -- date not complete -> no html formating or micro-tagging of date string elseif datecode == 'MD' then timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], datenum[3] ) class = '' -- date not complete -> no html formating or micro-tagging of date string else return '' -- format not supported end -- ========================================================== -- === Create Date String using in chosen language -- ========================================================== -- which form should the date take? -- Use langSwitch to pick formating for each language local langDateForm = langSwitch(i18n.DateLang, lang) -- special case of French and Gallic dates, which require different date format for the 1st day of the month if datenum[3]==1 and (langDateForm=='fr-form' or langDateForm=='ga-form') then langDateForm = langDateForm .. '1' -- ordinal form for the first day of the month end -- special case of Basque dates, which require different date format for the 1st, 11th, 21st and 31st day of the month if langDateForm=='eu-form' then if (datenum[3]==1 or datenum[3]==21) then langDateForm = 'eu-form01' elseif (datenum[3]==11 or datenum[3]==31) then langDateForm = 'eu-form11' end end -- Look up country specific format input to {{#time}} function local dFormat = i18n.DateFormat[langDateForm][datecode] -- overwrite default grammatical case of the month (applies mostly to Slavic languages) if (case=='gen') then -- CAUTION: at the moment i18n.DateFormat uses "F" only as month name, but this might change and this operation does not check if 'F' is in "" brackets or not, so if some language starts using 'F' in "" than this will not work for that language dFormat = dFormat:gsub("F", "xg"); end if (case=='nom') then -- CAUTION: at the moment i18n.DateFormat uses "xg" only as month name, but this might change and this operation does not check if 'xg' is in "" brackets or not, so if some language starts using 'xg' in "" than this will not work for that language dFormat = dFormat:gsub("xg", "F"); end if ((lang=='ru' or lang=='pl' or lang=='cs' or lang=='sl' or lang=='sk') and (case=='loc' or case=='ins')) or (lang=='fi' and (case=='ptv' or case=='ine'or case=='ela'or case=='ill') ) then local monthEn = mw.language.new('en'):formatDate( "F", timeStamp) -- month name in English -- month name using proper case and language. It relies on messages stored in MediaWiki namespace for some cases and languages -- That is why this IF statement uses "lang" not "langDateForm" variable to decide local monthMsg = mw.message.new( string.format('%s-%s', monthEn, case ) ):inLanguage( lang ) if not monthMsg:isDisabled() then -- make sure it exists local month=monthMsg:plain() dFormat = dFormat:gsub('F', '"'..month..'"'); -- replace default month with month name we already looked up dFormat = dFormat:gsub('xg', '"'..month..'"'); end end -- Special case related to Quechua and Kichwa languages -- see https://commons.wikimedia.org/wiki/Template_talk:Date#Quechua from 2014 if (lang=='qu' or lang=='qug') and case=='nom' then dFormat = dFormat:gsub('F"pi"', 'F'); end -- Lua only date formating using {{#time}} parser function (new) -- prefered call which gives "Lua error: too many language codes requested." on the [[Module talk:Date/sandbox/testcases]] page --local datestr = mw.language.new(lang):formatDate( dFormat, timeStamp) local datestr = mw.getCurrentFrame():callParserFunction( "#time", { dFormat, timeStamp, lang } ) -- Another special case related to Thai solar calendar if lang=='th' and datenum[1]~= nil and datenum[1]<=1940 then -- As of 2014 {{#time}} parser function did not resolve those cases properly -- See https://en.wikipedia.org/wiki/Thai_solar_calendar#New_year for reference -- Disable once https://bugzilla.wikimedia.org/show_bug.cgi?id=66648 is fixed if datecode=='Y' then -- date is ambiguous datestr = string.format('%04i หรือ %04i', datenum[1]+542, datenum[1]+543 ) elseif datenum[2]<=3 then -- year is wrong (one too many) datestr = datestr:gsub( string.format('%04i', datenum[1]+543), string.format('%04i', datenum[1]+542 ) ) end end -- If year<1000 than either keep it padded to the length of 4 digits or trim it -- decide if the year will stay padded with zeros (for years in 0-999 range) if datenum[1]~= nil and datenum[1]<1000 then local trim = yesno(trim_year,nil) if trim == nil then local YMin, YMax = trim_year:match( '(%d+)-(%d+)' ) trim = (YMin~=nil and datenum[1]>=tonumber(YMin) and datenum[1]<=tonumber(YMax)) end -- If the date form isn't the Thai solar calendar, don't zero pad years in the range of 100-999. -- If at some point support for Islamic/Hebrew/Japanese years is added, they may need to be skipped as well. if trim then --local yearStr1 = mw.language.new(lang):formatDate( 'Y', timeStamp) local yearStr1 = mw.getCurrentFrame():callParserFunction( "#time", { 'Y', timeStamp, lang } ) --local yearStr1 = datestr:match( '%d%d%d%d' ) -- 4 digits in a row (in any language) - that must be a year local yearStr2 = yearStr1 local zeroStr = mw.ustring.sub(yearStr1,1,1) for i=1,3 do -- trim leading zeros if mw.ustring.sub(yearStr2,1,1)==zeroStr then yearStr2 = mw.ustring.sub(yearStr2, 2, 5-i) else break end end datestr = datestr:gsub( yearStr1, yearStr2 ) --datestr = string.format('%s (%s, %s)', datestr, yearStr1, yearStr2 ) end end -- append timezone if present if datevec[7] ~= '' and (datecode == 'YMDHMS' or datecode == 'YMDHM') then local tzstr, tzhournum = '', tonumber(datevec[7]) if tzhournum < 0 then tzstr = '−' else tzstr = '+' end tzstr = tzstr..string.format("%02d", math.abs(tzhournum))..':' if datevec[8] ~= '' then tzstr = tzstr..datevec[8] else tzstr = tzstr..'00' end datestr = datestr..' '..tzstr end -- html formating and tagging of date string if class ~= '' then local DateHtmlTags = '<span style="white-space:nowrap"><time class="%s" datetime="%s">%s</time></span>' datestr = DateHtmlTags:format(class, timeStamp, datestr) end return datestr end return p 2qhdyl056nbwaexn38ogtoc8cvnzot8 模块:Fallback 828 14855 43061 2026-07-07T17:55:30Z 内存溢出的猫 7954 From [[zh:Module:Fallback]] 43061 Scribunto text/plain local p = {} local langlist = require('Module:Fallbacklist') function p.fblist(lang) -- list the full fallback chain from a language to en local fbtable = p.fallbackloop{ lang:lower() } table.insert(fbtable, 'default') table.insert(fbtable, 'en') return fbtable end function _inArray(x, t) for i, v in ipairs(t) do if v == x then return i end end return -1 end function p.fallbackloop(fbtable) --list of fallback languages in string format (more convenient than tables) local changes = false for i, j in ipairs(fbtable) do local seq = langlist[j] if seq then for k, l in ipairs(seq) do if _inArray(l, fbtable) == -1 then table.insert(fbtable, l) changes = true end end end end if changes then return p.fallbackloop(fbtable) end return fbtable end function p._langSwitch(args, lang) -- args: table of translations -- Return error if there is not default and no english version if not args.en and not args.default and args.nocat ~= '1' then return '<strong class="error">LangSwitch Error: no default</strong>[[Category:LangSwitch template without default version]]' end -- get language (either stated one or user's default language) if not lang then return '<strong class="error">LangSwitch Error: no lang</strong>' -- must become proper error end -- get the list of accpetable language (lang + those in lang's fallback chain) and check their content local parselist = p.fblist(lang) for i, k in ipairs(parselist) do if args[k] == '~' then return '' end if args[k] and args[k] ~= '' then return args[k] end end end function p.langSwitch(frame) -- version to be used from wikitext args = frame.args -- if no expected args provided than check parent template/module args if args.en==nil and args.default==nil and args.nocat==nil then args = mw.getCurrentFrame():getParent().args end if args.lang and args.lang ~= '' then lang = args.lang args.lang = nil else -- get user's chosen language lang = frame:preprocess( "{{int:lang}}" ) end return p._langSwitch(args, lang) end function p.fallbackpage(base, lang, formatting) local languages = p.fblist(lang) for i, lng in ipairs(languages) do if mw.title.new(base .. '/' .. lng).exists then if formatting == 'table' then return {base .. '/' .. lng, lng} -- returns name of the page + name of the language else return base .. '/' .. lng -- returns only the page end end end end function p.autotranslate(frame) -- logic for [[template:Autotranslate]] local args = frame.args if not args.lang or args.lang == '' then args.lang = frame:preprocess( "{{int:lang}}" ) -- get user's chosen language end -- find base page local base = args.base if not base or base == '' then return '<strong class="error">Base page not provided for autotranslate</strong>' end if string.sub(base,2,9) ~= 'emplate:' then base = 'Template:' .. base -- base provided without 'Template:' part end -- find base template language subpage local page = p.fallbackpage(base, args.lang) -- if (not page and base ~= args.base) then -- try the original args.base string. This case is only needed if base is not in template namespace page = p.fallbackpage(args.base, args.lang) end if not page then return string.format('<strong class="error">no fallback page found for autotranslate (base=[[%s]], lang=%s)</strong>', args.base, args.lang) end -- repack args in a standard table newargs = {} for field, value in pairs(args) do if field ~= 'base' then newargs[field] = value; end end -- Transclude {{page |....}} with template arguments the same as the ones passed to {{autotranslate}} template. return frame:expandTemplate{ title = page, args = newargs } end function p.translatelua(frame) local lang = frame.args.lang local page = require('Module:' .. mw.text.trim(frame.args[1])) -- page should only contain a simple of translations if not lang or mw.text.trim(lang) == '' then lang = frame:preprocess( "{{int:lang}}" ) end if frame.args[2] then page = page[mw.text.trim(frame.args[2])] end return p._langSwitch(page, lang) end function p.runTests() local toFallbackTest = require('Module:Fallback/tests/fallbacks') local result = true mw.log('Testing fallback chains') for i, t in ipairs(toFallbackTest) do local fbtbl = table.concat(p.fblist(t.initial), ', ') local expected = table.concat(t.expected, ', ') local ret = (fbtbl == expected) mw.log(i, ret and 'passed' or 'FAILED', t.initial, (not ret) and ('FAILED\nis >>' .. fbtbl .. '<<\nbut should be >>' .. expected .. '<<\n') or '') result = result and ret end return result end function p.showTemplateArguments(frame) -- list all input arguments of the template that calls "{{#invoke:Fallback|showTemplateArguments}}" local str = '' for name, value in pairs( mw.getCurrentFrame():getParent().args ) do if str=='' then str = string.format('%s=%s', name, value) -- argument #1 else str = string.format('%s, %s=%s', str, name, value) -- the rest end end return str end return p 5axdehna0wz2pp3u335pz05s6vo6av7 模块:I18n/date 828 14856 43062 2026-07-07T17:55:35Z 内存溢出的猫 7954 From [[zh:Module:I18n/date]] 43062 Scribunto text/plain --[[ __ __ _ _ ___ _ ___ __ _ _ | \/ | ___ __| |_ _| | ___ _|_ _/ |( _ ) _ __ / /_| | __ _| |_ ___ | |\/| |/ _ \ / _` | | | | |/ _ (_)| || |/ _ \| '_ \ / / _` |/ _` | __/ _ \ | | | | (_) | (_| | |_| | | __/_ | || | (_) | | | |/ / (_| | (_| | || __/ |_| |_|\___/ \__,_|\__,_|_|\___(_)___|_|\___/|_| |_/_/ \__,_|\__,_|\__\___| This Module handles per language customization of dates Copied from https://commons.wikimedia.org/wiki/Module:I18n/date used by Module:ISOdate, Module:Complex date, Module:WikidataIB Authors and Maintainers: * Jarekt ]] local p = {} --[[ Different languages use different date formats, and many formats are shared among whole families of languages. "DateLang" picks a cluster of languages associated with a single date format, based on the language to be used. All unlisted languages default to English form. Languages like "de-formal" follows regular language fallback chain and would default to German, and only if that does not exist then to English. ]] p.DateLang = { ['be'] = 'ru-form', -- Belarusian ['be-tarsk'] = 'ru-form', -- Belarusian (Tara۫ievica) ['bn'] = 'en-form', -- Bengali ['bpy'] = 'bpy-form', -- Bishnupuriya Manipuri ['ce'] = 'ce-form', -- Chechen ['cs'] = 'cs-form', -- Czech ['da'] = 'de-form', -- Danish ['de'] = 'de-form', -- German ['el'] = 'ru-form', -- Greek ['en'] = 'en-form', -- English ['eo'] = 'eo-form', -- Esperanto ['es'] = 'es-form', -- Spanish ['et'] = 'de-form', -- Estonian ['eu'] = 'eu-form', -- Basque ['fa'] = 'he-form', -- Persian ['fi'] = 'fi-form', -- Finnish ['fr'] = 'fr-form', -- French ['ga'] = 'ga-form', -- Gallic ['gl'] = 'es-form', -- Galician based on https://translatewiki.net/wiki/MediaWiki:Pagetriage-info-timestamp-date-format/gl ['hi'] = 'en-form', -- Hindi ['he'] = 'he-form', -- Hebrew ['hr'] = 'hr-form', -- Croatian ['hu'] = 'hu-form', -- Hungarian ['hsb'] = 'cs-form', -- Upper Sorbian ['ia'] = 'ia-form', -- Interlingua ['is'] = 'de-form', -- Icelandic ['ja'] = 'zh-form', -- Japanese ['kn'] = 'kn-form', -- Kannada ['ko'] = 'ko-form', -- Korean ['lt'] = 'lt-form', -- Lithuanian ['lv'] = 'lv-form', -- Latvian ['mk'] = 'en-form', -- Macedonian ['ml'] = 'ml-form', -- Malayalam ['mr'] = 'mr-form', -- Marathi ['new'] = 'new-form', -- Newari ['nn'] = 'de-form', -- Norwegian Nynorsk ['no'] = 'de-form', -- Norwegian (bokm欩 ['oc'] = 'oc-form', -- Occitan ['pa'] = 'en-form', -- Punjabi ['pl'] = 'ru-form', -- Polish ['pt'] = 'es-form', -- Portuguese ['qu'] = 'qu-form', -- Quechua based on https://translatewiki.net/wiki/MediaWiki:Pagetriage-info-timestamp-date-format/qu ['qug'] = 'qug-form', -- Kichwa based on Template_talk:Date#Kichwa_.5Bqug.5D ['ru'] = 'ru-form', -- Russian ['sk'] = 'cs-form', -- Slovakian ['sl'] = 'sl-form', -- Slovene ['sr'] = 'hr-form', -- Serbian ['th'] = 'th-form', -- Thai solar calendar ['uk'] = 'ru-form', -- Ukrainian ['vi'] = 'vi-form', -- Vietnamese ['zh-hans'] = 'zh-form', -- Chinese } --[[ Date format parameter which will be passed to {{#time:}} parser function. It depends on the language and which parts of the date need to be displayed. Different forms are: * YMDHMS = stands for YYYY:MM:DD, HH:MM:SS format or equivalent * YMDHM = stands for YYYY:MM:DD, HH:MM format or equivalent * YMD = stands for YYYY:MM:DD format or equivalent * YM = stands for YYYY:MM (year-month) format or equivalent * MD = stands for MM:DD (month-day) format or equivalent * Y = stands for YYYY (year only) format or equivalent * M = stands for month name only The left hand side follows encoding used by {{#time}} parser function , see https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time for documentation. To summerize: * Y - 4-digit year, like "2017" * y - 2-digit year, like "17" * M - An abbreviation of the month name, in the site language, like "Mar" * F - The full month name in the site language, like "March" * xg - Output the full month name in the genitive form for site languages that distinguish between genitive and nominative forms. This option is useful for many Slavic languages like Polish, Russian, Belarusian, Czech, Slovak, Slovene, Ukrainian, etc. * j - Day of the month, not zero-padded, like "1" * d - Day of the month, zero-padded, like "01" * a - "am" during the morning (00:00:00 → 11:59:59), "pm" otherwise (12:00:00 → 23:59:59). * A - Uppercase version of a above. * g - Hour in 12-hour format, not zero-padded. * h - Hour in 12-hour format, zero-padded. * G - Hour in 24-hour format, not zero-padded. * H - Hour in 24-hour format, zero-padded. * i - Minutes past the hour, zero-padded. * s - Seconds past the minute, zero-padded. Original set was developed to match the output of the pre-Lua {{date}} template, preserved as {{date/old}} ]] p.DateFormat = { -- day/month/year languages ['en-form'] = { YMDHMS='j F Y, H:i:s', YMDHM ='j F Y, H:i', YMD ='j F Y', YM ='F Y', MD ='j F', Y ='Y', M ='F' }, ['de-form'] = { YMDHMS='j. F Y, H:i:s', YMDHM ='j. F Y, H:i', YMD ='j. F Y', YM ='F Y', MD ='j. F', Y ='Y', M ='F' }, ['hr-form'] = { YMDHMS='j. F Y., H:i:s', YMDHM ='j. F Y., H:i', YMD ='j. F Y.', YM ='F Y.', MD ='j. F', Y ='Y.', M ='F' }, ['ml-form'] = { YMDHMS='j F Y, H:i:s', YMDHM ='j F Y, H:i', YMD ='j F Y', YM ='F Y', MD ='F j', Y ='Y', M ='F' }, ['th-form'] = { YMDHMS='j F "พ.ศ." xkY, H:i:s', YMDHM ='j F "พ.ศ." xkY, H:i', YMD ='j F "พ.ศ." xkY', YM ='F "พ.ศ." xkY', MD ='j F', Y ='"พ.ศ." xkY', M ='F' }, ['fi-form'] = { YMDHMS='j. F"ta" Y, H:i:s', YMDHM ='j. F"ta" Y, H:i', YMD ='j. F"ta" Y', YM ='F Y', MD ='j. F"ta"', Y ='Y', M ='F' }, ['es-form'] = { YMDHMS='j "de" F "de" Y, H:i:s', YMDHM ='j "de" F "de" Y, H:i', YMD ='j "de" F "de" Y', YM ='F "de" Y', MD ='j "de" F', Y ='Y', M ='F' }, ['oc-form'] = { YMDHMS='j F "de" Y, H:i:s', YMDHM ='j F "de" Y, H:i', YMD ='j F "de" Y', YM ='F "de" Y', MD ='j F', Y ='Y', M ='F' }, ['ia-form'] = { YMDHMS='j "de" F Y, H:i:s', YMDHM ='j "de" F Y, H:i', YMD ='j "de" F Y', YM ='F Y', MD ='j "de" F', Y ='Y', M ='F' }, ['eo-form'] = { YMDHMS='"la" j"-a de" F Y, H:i:s', YMDHM ='"la" j"-a de" F Y, H:i', YMD ='"la" j"-a de" F Y', YM ='F Y', MD ='"la" j"-a de" F', Y ='Y', M ='F' }, ['vi-form'] = { YMDHMS='j F "năm" Y "lúc" H:i:s', YMDHM ='j F "năm" Y "lúc" H:i', YMD ='j F "năm" Y', YM ='F "năm" Y', MD ='j F', Y ='Y', M ='F' }, ['qu-form'] = { YMDHMS='j "ñiqin" F"pi" Y "watapi", H:i:s', YMDHM ='j "ñiqin" F"pi" Y "watapi", H:i', YMD ='j "ñiqin" F"pi" Y "watapi"', YM ='F"pi" Y "watapi"', MD ='j "ñiqin" F"pi"', Y ='Y', M ='F' }, ['qug-form'] = { YMDHMS='j "niki" F"pi" Y "watapi", H:i:s', YMDHM ='j "niki" F"pi" Y "watapi", H:i', YMD ='j "niki" F"pi" Y "watapi"', YM ='F"pi" Y "watapi"', MD ='j "niki" F"pi"', Y ='Y', M ='F' }, ['he-form'] = { YMDHMS='"<span dir=rtl>"j xg Y"</span>", H:i:s', YMDHM ='"<span dir=rtl>"j xg Y"</span>", H:i', YMD ='"<span dir=rtl>"j xg Y"</span>"', YM ='"<span dir=rtl>"F Y"</span>"', MD ='"<span dir=rtl>"j xg"</span>"', Y ='Y', M ='"<span dir=rtl>"F"</span>"' }, -- French and Gallic languages require different form for first day of the month and -- different for the other days ['fr-form'] = { YMDHMS='j F Y, H:i:s', YMDHM ='j F Y, H:i', YMD ='j F Y', YM ='F Y', MD ='j F', Y ='Y', M ='F' }, ['ga-form'] = { YMDHMS='j F Y, H:i:s', YMDHM ='j F Y, H:i', YMD ='j F Y', YM ='F Y', MD ='j F', Y ='Y', M ='F' }, ['fr-form1'] = { -- 1st of the month form YMDHMS='j"<sup>er</sup>" F Y, H:i:s', YMDHM ='j"<sup>er</sup>" F Y, H:i', YMD ='j"<sup>er</sup>" F Y', YM ='F Y', MD ='j"<sup>er</sup>" F', Y ='Y', M ='F' }, ['ga-form1'] = { -- 1st of the month form YMDHMS='j"<sup>ú</sup>" F Y, H:i:s', YMDHM ='j"<sup>ú</sup>" F Y, H:i', YMD ='j"<sup>ú</sup>" F Y', YM ='F Y', MD ='j"<sup>ú</sup>" F', Y ='Y', M ='F' }, -- day/month/year Slavic languages ['ru-form'] = { YMDHMS='j xg Y, H:i:s', YMDHM ='j xg Y, H:i', YMD ='j xg Y', YM ='F Y', MD ='j xg', Y ='Y', M ='F' }, ['cs-form'] = { YMDHMS='j. xg Y, H:i:s', YMDHM ='j. xg Y, H:i', YMD ='j. xg Y', YM ='F Y', MD ='j. xg', Y ='Y', M ='F' }, ['sl-form'] = { YMDHMS='j. xg Y "ob" H:i:s', YMDHM ='j. xg Y "ob" H:i', YMD ='j. xg Y', YM ='F Y', MD ='j. xg', Y ='Y', M ='F' }, -- year/month/day languages ['zh-form'] = { YMDHMS='Y年Fj日, H:i:s', YMDHM ='Y年Fj日, H:i', YMD ='Y年Fj日', YM ='Y年F', MD ='Fj日', Y ='Y年', M ='F' }, ['ko-form'] = { YMDHMS='Y년 F j일, H:i:s', YMDHM ='Y년 F j일, H:i', YMD ='Y년 F j일', YM ='Y년 F', MD ='F j일', Y ='Y년', M ='F' }, ['hu-form'] = { YMDHMS='Y. F j., H:i:s', YMDHM ='Y. F j., H:i', YMD ='Y. F j.', YM ='Y. F', MD ='F j.', Y ='Y', M ='F' }, ['lt-form'] = { YMDHMS='Y "m". F j "d"., H:i:s', YMDHM ='Y "m". F j "d"., H:i', YMD ='Y "m". F j "d".', YM ='Y "m". F', MD ='F j "d".', Y ='Y "m".', M ='F' }, ['eu-form'] = { YMDHMS='Y"ko" F"ren" j"a", H:i:s', YMDHM ='Y"ko" F"ren" j"a", H:i', YMD ='Y"ko" F"ren" j"a"', YM ='Y"ko" F', MD ='F"ren" j"a"', Y ='Y', M ='F' }, ['eu-form01'] = { -- 1st and 21st of the month uses different form YMDHMS='Y"ko" F"ren" j"ea", H:i:s', YMDHM ='Y"ko" F"ren" j"ea", H:i', YMD ='Y"ko" F"ren" j"ea"', YM ='Y"ko" F', MD ='F"ren" j"ea"', Y ='Y', M ='F' }, ['eu-form11'] = { -- 11th and 31st of the month uses different form YMDHMS='Y"ko" F"ren" j, H:i:s', YMDHM ='Y"ko" F"ren" j, H:i', YMD ='Y"ko" F"ren" j', YM ='Y"ko" F', MD ='F"ren" j', Y ='Y', M ='F' }, ['ce-form'] = { YMDHMS='Y "шаран" j F, H:i:s', YMDHM ='Y "шаран" j F, H:i', YMD ='Y "шаран" j F', YM ='Y "шаран" F', MD ='j F', Y ='Y "шо"', M ='F' }, -- year/day/month languages ['lv-form'] = { YMDHMS='Y". gada" j. F, H:i:s', YMDHM ='Y". gada" j. F, H:i', YMD ='Y". gada" j. F', YM ='Y". gada" F', MD ='j. F', Y ='Y". gada"', M ='F' }, -- month/day/year languages ['kn-form'] = { YMDHMS='F j, Y, H:i:s', YMDHM ='F j, Y, H:i', YMD ='F j, Y', YM ='F, Y', MD ='F j', Y ='Y', M ='F' }, ['bpy-form']= { YMDHMS='F j, মারি Y, H:i:s', YMDHM ='F j, মারি Y, H:i', YMD ='F j, মারি Y', YM ='F, মারি Y', MD ='F j', Y ='মারি Y', M ='F' }, ['mr-form'] = { YMDHMS='F j, इ.स. Y, H:i:s', YMDHM ='F j, इ.स. Y, H:i', YMD ='F j, इ.स. Y', YM ='F, इ.स. Y', MD ='F j', Y ='इ.स. Y', M ='F' }, ['new-form']= { YMDHMS='F j, ई सं Y, H:i:s', YMDHM ='F j, ई सं Y, H:i', YMD ='F j, ई सं Y', YM ='F, ई सं Y', MD ='F j', Y ='ई सं Y', M ='F' }, } return p pr3pw5ufcfxz8awpmk7xr2i84szxbpx 模块:Fallbacklist 828 14857 43063 2026-07-07T17:55:38Z 内存溢出的猫 7954 From [[zh:Module:Fallbacklist]] 43063 Scribunto text/plain return { -- crh (Crimean Tatar) cluster: crh-cyrl , crh-latn -> crh (Crimean Tatar) ['crh'] = {'crh-latn'}, ['crh-cyrl'] = {'crh'}, ['crh-latn'] = {'crh'}, -- de (German) cluster: ['als'] = {'gsw', 'de'}, -- Alemannisch ['bar'] = {'de'}, -- Bavarian ['de-at'] = {'de'}, -- Austrian German ['de-ch'] = {'de'}, -- Swiss High German ['de-formal'] = {'de'}, -- German (formal address) ['dsb'] = {'de'}, -- Lower Sorbian ['frr'] = {'de'}, -- Northern Frisian ['hsb'] = {'de'}, -- Upper Sorbian ['ksh'] = {'de'}, -- Colognian ['lb'] = {'de'}, -- Luxembourgish ['nds'] = {'nds-nl', 'de'}, -- Low German ['nds-nl'] = {'nds', 'nl'}, -- Low Saxon (Netherlands) ['pdc'] = {'de'}, -- Deitsch ['pdt'] = {'nds', 'de'}, -- Plautdietsch ['pfl'] = {'de'}, -- Pälzisch ['sli'] = {'de'}, -- Lower Silesian ['stq'] = {'de'}, -- Seeltersk ['vmf'] = {'de'}, -- Upper Franconian -- es (Spanish) cluster ['an'] = {'es'}, -- Aragonese ['arn'] = {'es'}, -- Mapuche ['ay'] = {'es'}, -- Aymara ['cbk-zam'] = {'es'}, -- Chavacano de Zamboanga ['gn'] = {'es'}, -- Guarani ['lad'] = {'es'}, -- Ladino ['nah'] = {'es'}, -- Nahuatl ['qu'] = {'es'}, -- Quechua ['qug'] = {'qu', 'es'}, -- Runa shimi -- et (Estonian) cluster ['liv'] = {'et'}, -- Līvõ kēļ ['vep'] = {'et'}, -- Veps ['vro'] = {'et'}, -- Võro ['fio-vro'] = {'vro'}, -- Võro -- fa (Persian) cluster ['bcc'] = {'fa'}, -- Southern Balochi ['bqi'] = {'fa'}, -- Bakhtiari ['glk'] = {'fa'}, -- Gilaki ['mzn'] = {'fa'}, -- Mazandarani -- fi (Finnish) cluster: ['fit'] = {'fi'}, -- meänkieli ['vot'] = {'fi'}, -- Votic -- fr (French) cluster: ['bm'] = {'fr'}, -- Bambara ['br'] = {'fr'}, -- Breton ['co'] = {'fr'}, -- Corsican ['ff'] = {'fr'}, -- Fulah ['frc'] = {'fr'}, -- Cajun French ['frp'] = {'fr'}, -- Franco-Provençal ['ht'] = {'fr'}, -- Haitian ['ln'] = {'fr'}, -- Lingala ['mg'] = {'fr'}, -- Malagasy ['pcd'] = {'fr'}, -- Picard ['sg'] = {'fr'}, -- Sango ['ty'] = {'fr'}, -- Tahitian ['wa'] = {'fr'}, -- Walloon ['wo'] = {'fr'}, -- Wolof -- hi (Hindi) cluster ['anp'] = {'hi'}, -- Angika ['may'] = {'hi'}, -- Maithili ['sa'] = {'hi'}, -- Sanskrit -- hif (Fiji Hindi) cluster: hif-deva , hif-latn -> hif (Fiji Hindi) ['hif'] = {'hif-latn'}, ['hif-deva'] = {'hif'}, ['hif-latn'] = {'hif'}, -- id (Indonesian) cluster ['min'] = {'id'}, -- Minangkabau ['ace'] = {'id'}, -- Achinese ['bug'] = {'id'}, -- Buginese ['bjn'] = {'id'}, -- Banjar ['jv'] = {'id'}, -- Javanese ['su'] = {'id'}, -- Sundanese ['map-bms'] = {'jv', 'id'}, -- Basa Banyumasan -- ike (Eastern Canadian Inuktitut) cluster: ike-cans , ike-latn -> ike (Eastern Canadian Inuktitut) ['ike-cans'] = {'ik'}, ['ike-latn'] = {'ik'}, -- it (Italian) cluster ['egl'] = {'it'}, -- Emiliàn ['eml'] = {'it'}, -- Emiliano-Romagnolo ['fur'] = {'it'}, -- Friulian ['lij'] = {'it'}, -- Ligure ['lmo'] = {'it'}, -- lumbaart ['nap'] = {'it'}, -- Neapolitan ['pms'] = {'it'}, -- Piedmontese ['rgn'] = {'it'}, -- Romagnol ['scn'] = {'it'}, -- Sicilian ['vec'] = {'it'}, -- vèneto -- kk (Kazakh) cluster: -- kk-arab , kk-cyrl , kk-latn , kk-cn , kk-kz , kk-tr -> kk (Kazakh) ['kk'] = {'kk-cyrl'}, -- Kazakh ['kk-arab'] = {'kk-cyrl', 'kk'}, -- Kazakh (Arabic script) ['kk-cn'] = {'kk-arab', 'kk-cyrl', 'kk'}, -- Kazakh (China) ['kk-cyrl'] = {'kk'}, -- Kazakh (Cyrillic script) ['kk-kz'] = {'kk', 'kk-cyrl'}, -- Kazakh (Kazakhstan) ['kk-latn'] = {'kk'}, -- Kazakh (Latin script) ['kk-tr'] = {'kk-latn', 'kk'}, -- Kazakh (Turkey) ['kaa'] = {'kk-latn', 'kk-cyrl'}, -- Kara-Kalpak -- ku (Kurdish) cluster: ku-latn , ku-arab -> ku (Kurdish) ['ku'] = {'ku-latn'}, ['ku-arab'] = {'ckb', 'ku'}, -- كوردي (عەرەبی) ['ku-latn'] = {'ku'}, ['ckb'] = {'ku'}, -- nl (Dutch) cluster ['af'] = {'nl'}, -- Afrikaans ['fy'] = {'nl'}, -- Western Frisian ['li'] = {'nl'}, -- Liechtenstein ['nl-informal']= {'nl'}, -- Nederlands (informeel) ['vls'] = {'nl'}, -- Vlaams ['zea'] = {'nl'}, -- Zeeuws --pl (Polish) cluster ['csb'] = {'pl'}, -- Kashubian ['szl'] = {'pl'}, -- Silesian -- pt (Portuguese) cluster ['gl'] = {'pt'}, -- Galician ['mwl'] = {'pt'}, -- Mirandese ['pt-br'] = {'pt'}, -- Brazilian Portuguese -- ro (Romanian) cluster ['mo'] = {'ro'}, -- Moldavian ['rmy'] = {'ro'}, -- Romani -- ru (Russian) cluster ['ab'] = {'ru'}, -- Abkhazian ['av'] = {'ru'}, -- Avaric ['ba'] = {'ru'}, -- Bashkir ['be-tarask'] = {'ru'}, -- Belorussian ['ce'] = {'ru'}, -- Chechen ['crh-cyrl'] = {'ru'}, -- Crimean Tatar (Cyrillic script) ['cv'] = {'ru'}, -- Chuvash ['inh'] = {'ru'}, -- Ingush ['koi'] = {'ru'}, -- Komi-Permyak ['krc'] = {'ru'}, -- Karachay-Balkar ['kv'] = {'ru'}, -- Komi ['lbe'] = {'ru'}, -- лакку ['lez'] = {'ru'}, -- Lezghian ['mhr'] = {'ru'}, -- Eastern Mari ['mrj'] = {'ru'}, -- Hill Mari ['myv'] = {'ru'}, -- Erzya ['os'] = {'ru'}, -- Ossetic ['sah'] = {'ru'}, -- Sakha ['tt'] = {'tt-cyrl', 'ru'}, -- Tatar ['tt-cyrl'] = {'ru'}, -- Tatar (Cyrillic script) ['udm'] = {'ru'}, -- Udmurt ['xal'] = {'ru'}, -- Kalmyk -- ruq (Megleno Romanian) cluster: ruq-cyrl , ruq-grek , ruq-latn -> ruq (Megleno Romanian) ['ruq'] = {'ruq-latn'}, -- Megleno-Romanian ['ruq-cyrl'] = {'ruq', 'mk'}, ['ruq-grek'] = {'ruq'}, ['rug-latn'] = {'ro', 'ruq'}, -- Megleno-Romanian (Latin script) -- sr (Serbian) cluster: sr-ec , sr-el -> sr (Serbian) ['sr'] = {'sr-ec'}, ['sr-ec'] = {'sr'}, ['sr-el'] = {'sr'}, -- tg (Tajik) cluster: tg-cyrl , tg-latn -> tg (Tajik) ['tg'] = {'tg-cyrl'}, ['tg-cyrl'] = {'tg'}, ['tg-latn'] = {'tg'}, -- tr (Turkish) cluster ['gag'] = {'tr'}, -- Gagauz ['kiu'] = {'tr'}, -- Kirmanjki ['lzz'] = {'tr'}, -- Lazuri -- tt (Tatar) cluster: tt-cyrl , tt-latn -> tt (Tatar) ['tt-cyrl'] = {'tt'}, ['tt-latn'] = {'tt'}, -- zh (Chinese) cluster ['gan'] = {'gan-hant', 'zh-hant'}, -- Gan ['gan-hans'] = {'zh-hans'}, -- Simplified Gan script ['gan-hant'] = {'zh-hant'}, -- Traditional Gan script ['ii'] = {'zh-cn'}, -- Sichuan Yi ['wuu'] = {'zh-hans'}, -- Wu ['za'] = {'zh-hans'}, -- Zhuang ['zh-hans'] = {'zh-cn', 'zh'}, -- Simplified Chinese ['zh-hant'] = {'zh'}, -- Traditional Chinese ['zh'] = {'zh-hans'}, ['zh-cn'] = {'zh-hans'}, -- Chinese (China) ['zh-hk'] = {'zh-hant'}, -- Chinese (Hong Kong) ['zh-mo'] = {'zh-hk', 'zh-hant'}, -- 中文(澳門) ['zh-my'] = {'zh-sg', 'zh-hans'}, -- 中文(马来西亚)‎ ['zh-sg'] = {'zh-hans'}, -- Chinese (Singapore) ['zh-tw'] = {'zh-hant'}, -- Chinese (Taiwan) ['zh-classical'] = {'lzh'}, -- Literary Chinese ['zh-min-nan'] = {'nan'}, -- Chinese (Min Nan) -> Min Nan Chinese ['zh-yue'] = {'yue'}, -- ? Cantonese -> Cantonese ------------------------ --------- misc --------- ------------------------ ['arz'] = {'ar'}, -- Egyptian Arabic -> Arabic ['azb'] = {'az'}, -- Southern Azerbaijani -> Azerbaijani ['be-x-old'] = {'be-tarask'}, -- be-x-old -> be-tarask (wrong to correct Taraškievica form of Belarusian orthography) ['bh'] = {'bho'}, -- Bihari -> Bhojpuri ['bpy'] = {'bn'}, -- Bishnupria Manipuri -> Bengali -- da ['jut'] = {'da'}, -- Jutish -> Danish ['kl'] = {'da'}, -- Kalaallisut -> Danish ['en-gb'] = {'en'}, ['yi'] = {'he'}, -- Yiddish -> Hebrew ['iu'] = {'ike-cans'}, -- Inuktitut -> Eastern Canadian (Aboriginal syllabics) ['xmf'] = {'ka'}, -- Mingrelian -> Georgian ['kbd'] = {'kbd-cyrl'}, -- Kabardian -> Адыгэбзэ ['tcy'] = {'kn'}, -- Tulu -> Kannada ['ko-kp'] = {'ko'}, -- 한국어 (조선) -> Korean ['ks'] = {'ks-arab'}, -- Kashmiri -> Kashmiri (Arabic script) -- lt ['bat-smg'] = {'sgs', 'lt'}, -- Samogitian -> Lithuanian ['sgs'] = {'lt'}, -- Samogitian -> Lithuanian ['ltg'] = {'lv'}, -- Latvian -> Latgalian ['dtp'] = {'ms'}, -- Central Dusun -> Malay ['no'] = {'nb'}, -- Norwegian (bokmål) -> Norwegian Bokmål ['roa-rup'] = {'rup'}, -- ? Aromanian -> Aromanian ['aln'] = {'sq'}, -- Gheg Albanian -> Albanian ['ug'] = {'ug-arab'}, -- Uyghur -> Uyghur (Arabic script) ['khw'] = {'ur'}, -- Khowar -> Urdu ['rue'] = {'uk'}, -- Rusyn -> Ukrainian } mqiv2t4e0vpzseojvn9n3d3lp3cyq0m 模板:ISOdate 10 14858 43064 2026-07-07T17:56:46Z 内存溢出的猫 7954 From [[zh:Template:ISOdate]] 43064 wikitext text/x-wiki <includeonly>{{#invoke:Date_Convert|ISODate}}</includeonly><noinclude> {{Doc}} </noinclude> 8f9nl8wnmn6m8u3jm8b1ucssp2ecwx1