Module:TNT
Documentation for this module may be created at Module:TNT/doc
1 --
2 -- INTRO: (!!! DO NOT RENAME THIS PAGE !!!)
3 -- This module allows any template or module to be copy/pasted between
4 -- wikis without any translation changes. All translation text is stored
5 -- in the global Data:*.tab pages on Commons, and used everywhere.
6 --
7 -- SEE: https://www.mediawiki.org/wiki/Multilingual_Templates_and_Modules
8 --
9 -- ATTENTION:
10 -- Please do NOT rename this module - it has to be identical on all wikis.
11 -- This code is maintained at https://www.mediawiki.org/wiki/Module:TNT
12 -- Please do not modify it anywhere else, as it may get copied and override your changes.
13 -- Suggestions can be made at https://www.mediawiki.org/wiki/Module_talk:TNT
14 --
15 -- DESCRIPTION:
16 -- The "msg" function uses a Commons dataset to translate a message
17 -- with a given key (e.g. source-table), plus optional arguments
18 -- to the wiki markup in the current content language.
19 -- Use lang=xx to set language. Example:
20 --
21 -- {{#invoke:TNT | msg
22 -- | I18n/Template:Graphs.tab <!-- https://commons.wikimedia.org/wiki/Data:I18n/Template:Graphs.tab -->
23 -- | source-table <!-- uses a translation message with id = "source-table" -->
24 -- | param1 }} <!-- optional parameter -->
25 --
26 --
27 -- The "doc" function will generate the <templatedata> parameter documentation for templates.
28 -- This way all template parameters can be stored and localized in a single Commons dataset.
29 -- NOTE: "doc" assumes that all documentation is located in Data:Templatedata/* on Commons.
30 --
31 -- {{#invoke:TNT | doc | Graph:Lines }}
32 -- uses https://commons.wikimedia.org/wiki/Data:Templatedata/Graph:Lines.tab
33 -- if the current page is Template:Graph:Lines/doc
34 --
35
36 local p = {}
37 local i18nDataset = 'I18n/Module:TNT.tab'
38
39 -- Forward declaration of the local functions
40 local sanitizeDataset, loadData, link, formatMessage
41
42 function p.msg(frame)
43 local dataset, id
44 local params = {}
45 local lang = nil
46 for k, v in pairs(frame.args) do
47 if k == 1 then
48 dataset = mw.text.trim(v)
49 elseif k == 2 then
50 id = mw.text.trim(v)
51 elseif type(k) == 'number' then
52 table.insert(params, mw.text.trim(v))
53 elseif k == 'lang' and v ~= '_' then
54 lang = mw.text.trim(v)
55 end
56 end
57 return formatMessage(dataset, id, params, lang)
58 end
59
60 -- Identical to p.msg() above, but used from other lua modules
61 -- Parameters: name of dataset, message key, optional arguments
62 -- Example with 2 params: format('I18n/Module:TNT', 'error_bad_msgkey', 'my-key', 'my-dataset')
63 function p.format(dataset, key, ...)
64 local checkType = require('libraryUtil').checkType
65 checkType('format', 1, dataset, 'string')
66 checkType('format', 2, key, 'string')
67 return formatMessage(dataset, key, {...})
68 end
69
70
71 -- Identical to p.msg() above, but used from other lua modules with the language param
72 -- Parameters: language code, name of dataset, message key, optional arguments
73 -- Example with 2 params: formatInLanguage('es', I18n/Module:TNT', 'error_bad_msgkey', 'my-key', 'my-dataset')
74 function p.formatInLanguage(lang, dataset, key, ...)
75 local checkType = require('libraryUtil').checkType
76 checkType('formatInLanguage', 1, lang, 'string')
77 checkType('formatInLanguage', 2, dataset, 'string')
78 checkType('formatInLanguage', 3, key, 'string')
79 return formatMessage(dataset, key, {...}, lang)
80 end
81
82 -- Obsolete function that adds a 'c:' prefix to the first param.
83 -- "Sandbox/Sample.tab" -> 'c:Data:Sandbox/Sample.tab'
84 function p.link(frame)
85 return link(frame.args[1])
86 end
87
88 function p.doc(frame)
89 local dataset = 'Templatedata/' .. sanitizeDataset(frame.args[1])
90 return frame:extensionTag('templatedata', p.getTemplateData(dataset)) ..
91 formatMessage(i18nDataset, 'edit_doc', {link(dataset)})
92 end
93
94 function p.getTemplateData(dataset)
95 -- TODO: add '_' parameter once lua starts reindexing properly for "all" languages
96 local data = loadData(dataset)
97 local names = {}
98 for _, field in pairs(data.schema.fields) do
99 table.insert(names, field.name)
100 end
101
102 local params = {}
103 local paramOrder = {}
104 for _, row in pairs(data.data) do
105 local newVal = {}
106 local name = nil
107 for pos, val in pairs(row) do
108 local columnName = names[pos]
109 if columnName == 'name' then
110 name = val
111 else
112 newVal[columnName] = val
113 end
114 end
115 if name then
116 params[name] = newVal
117 table.insert(paramOrder, name)
118 end
119 end
120
121 -- Work around json encoding treating {"1":{...}} as an [{...}]
122 params['zzz123']=''
123
124 local json = mw.text.jsonEncode({
125 params=params,
126 paramOrder=paramOrder,
127 description=data.description
128 })
129
130 json = string.gsub(json,'"zzz123":"",?', "")
131
132 return json
133 end
134
135 -- Local functions
136
137 sanitizeDataset = function(dataset)
138 if not dataset then
139 return nil
140 end
141 dataset = mw.text.trim(dataset)
142 if dataset == '' then
143 return nil
144 elseif string.sub(dataset,-4) ~= '.tab' then
145 return dataset .. '.tab'
146 else
147 return dataset
148 end
149 end
150
151 loadData = function(dataset, lang)
152 dataset = sanitizeDataset(dataset)
153 if not dataset then
154 error(formatMessage(i18nDataset, 'error_no_dataset', {}))
155 end
156
157 -- Give helpful error to thirdparties who try and copy this module.
158 if not mw.ext or not mw.ext.data or not mw.ext.data.get then
159 error('Missing JsonConfig extension; Cannot load https://commons.wikimedia.org/wiki/Data:' .. dataset)
160 end
161
162 local data = mw.ext.data.get(dataset, lang)
163
164 if data == false then
165 if dataset == i18nDataset then
166 -- Prevent cyclical calls
167 error('Missing Commons dataset ' .. i18nDataset)
168 else
169 error(formatMessage(i18nDataset, 'error_bad_dataset', {link(dataset)}))
170 end
171 end
172 return data
173 end
174
175 -- Given a dataset name, convert it to a title with the 'commons:data:' prefix
176 link = function(dataset)
177 return 'c:Data:' .. mw.text.trim(dataset or '')
178 end
179
180 formatMessage = function(dataset, key, params, lang)
181 for _, row in pairs(loadData(dataset, lang).data) do
182 local id, msg = unpack(row)
183 if id == key then
184 local result = mw.message.newRawMessage(msg, unpack(params or {}))
185 return result:plain()
186 end
187 end
188 if dataset == i18nDataset then
189 -- Prevent cyclical calls
190 error('Invalid message key "' .. key .. '"')
191 else
192 error(formatMessage(i18nDataset, 'error_bad_msgkey', {key, link(dataset)}))
193 end
194 end
195
196 return p