1if not modules then modules = { } end modules ['core-con'] = {
2 version = 1.001,
3 comment = "companion to core-con.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15local floor = math.floor
16local osdate, ostime, ostimezone = os.date, os.time, os.timezone
17local concat, insert, reverse = table.concat, table.insert, table.reverse
18local lower, upper, rep, match, gsub, gmatch = string.lower, string.upper, string.rep, string.match, string.gsub, string.gmatch
19local utfchar, utfbyte = utf.char, utf.byte
20local tonumber, tostring, type, rawset = tonumber, tostring, type, rawset
21local P, S, R, Cc, Cf, Cg, Ct, Cs, C, V, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.Cs, lpeg.C, lpeg.V, lpeg.Carg
22local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
23local div, mod = math.div, math.mod
24
25local context = context
26local commands = commands
27local implement = interfaces.implement
28
29local settings_to_array = utilities.parsers.settings_to_array
30local allocate = utilities.storage.allocate
31local setmetatableindex = table.setmetatableindex
32local formatters = string.formatters
33local variables = interfaces.variables
34local constants = interfaces.constants
35local addformatter = utilities.strings.formatters.add
36
37local texset = tex.set
38
39converters = converters or { }
40local converters = converters
41
42languages = languages or { }
43local languages = languages
44
45local helpers = converters.helpers or { }
46converters.helpers = helpers
47
48local ctx_labeltext = context.labeltext
49local ctx_LABELTEXT = context.LABELTEXT
50local ctx_space = context.space
51local ctx_convertnumber = context.convertnumber
52local ctx_highordinalstr = context.highordinalstr
53
54converters.number = tonumber
55converters.numbers = tonumber
56
57implement { name = "number", actions = context }
58implement { name = "numbers", actions = context }
59
60
61
62local counters = allocate {
63 ['default'] = {
64 0x0061, 0x0062, 0x0063, 0x0064, 0x0065,
65 0x0066, 0x0067, 0x0068, 0x0069, 0x006A,
66 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
67 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
68 0x0075, 0x0076, 0x0077, 0x0078, 0x0079,
69 0x007A
70 },
71 ['slovenian'] = {
72 0x0061, 0x0062, 0x0063, 0x010D, 0x0064,
73 0x0065, 0x0066, 0x0067, 0x0068, 0x0069,
74 0x006A, 0x006B, 0x006C, 0x006D, 0x006E,
75 0x006F, 0x0070, 0x0072, 0x0073, 0x0161,
76 0x0074, 0x0075, 0x0076, 0x007A, 0x017E
77 },
78 ['spanish'] = {
79 0x0061, 0x0062, 0x0063, 0x0064, 0x0065,
80 0x0066, 0x0067, 0x0068, 0x0069, 0x006A,
81 0x006B, 0x006C, 0x006D, 0x006E, 0x00F1,
82 0x006F, 0x0070, 0x0071, 0x0072, 0x0073,
83 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
84 0x0079, 0x007A
85 },
86 ['russian'] = {
87 0x0430, 0x0431, 0x0432, 0x0433, 0x0434,
88 0x0435, 0x0436, 0x0437, 0x0438, 0x043a,
89 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
90 0x0440, 0x0441, 0x0442, 0x0443, 0x0444,
91 0x0445, 0x0446, 0x0447, 0x0448, 0x0449,
92 0x044d, 0x044e, 0x044f
93 },
94 ['greek'] = {
95
96
97
98
99
100 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5,
101 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA,
102 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
103 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5,
104 0x03C6, 0x03C7, 0x03C8, 0x03C9,
105 },
106 ['arabic'] = {
107 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
108 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
109 0x0643, 0x0644, 0x0645, 0x0646, 0x0633,
110 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
111 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
112 0x0636, 0x0638, 0x063A,
113 },
114 ['persian'] = {
115 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
116 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
117 0x06A9, 0x0644, 0x0645, 0x0646, 0x0633,
118 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
119 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
120 0x0636, 0x0638, 0x063A,
121 },
122 ['thai'] = {
123 0xE050, 0xE051, 0xE052, 0xE053, 0xE054,
124 0xE055, 0xE056, 0xE057, 0xE058, 0xE059
125 },
126 ['devanagari'] = {
127
128 0x0966, 0x0967, 0x0968, 0x0969, 0x096A,
129 0x096B, 0x096C, 0x096D, 0x096E, 0x096F
130 },
131 ['gurmurkhi'] = {
132 0x0A66, 0x0A67, 0x0A68, 0x0A69, 0x0A6A,
133 0x0A6B, 0x0A6C, 0x0A6D, 0x0A6E, 0x0A6F
134 },
135 ['gujarati'] = {
136 0x0AE6, 0x0AE7, 0x0AE8, 0x0AE9, 0x0AEA,
137 0x0AEB, 0x0AEC, 0x0AED, 0x0AEE, 0x0AEF
138 },
139 ['tibetan'] = {
140 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24,
141 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29
142 },
143 ['korean'] = {
144 0x3131, 0x3134, 0x3137, 0x3139, 0x3141,
145 0x3142, 0x3145, 0x3147, 0x3148, 0x314A,
146 0x314B, 0x314C, 0x314D, 0x314E
147 },
148 ['korean-parenthesis'] = {
149 0x3200, 0x3201, 0x3202, 0x3203, 0x3204,
150 0x3205, 0x3206, 0x3207, 0x3208, 0x3209,
151 0x320A, 0x320B, 0x320C, 0x320D
152 },
153 ['korean-circle'] = {
154 0x3260, 0x3261, 0x3262, 0x3263, 0x3264,
155 0x3265, 0x3266, 0x3267, 0x3268, 0x3269,
156 0x326A, 0x326B, 0x326C, 0x326D
157 },
158}
159
160languages.counters = counters
161
162counters['ar'] = counters['arabic']
163counters['gr'] = counters['greek']
164counters['g'] = counters['greek']
165counters['sl'] = counters['slovenian']
166counters['es'] = counters['spanish']
167counters['ru'] = counters['russian']
168counters['kr'] = counters['korean']
169counters['kr-p'] = counters['korean-parenthesis']
170counters['kr-c'] = counters['korean-circle']
171
172counters['thainumerals'] = counters['thai']
173counters['devanagarinumerals'] = counters['devanagari']
174counters['gurmurkhinumerals'] = counters['gurmurkhi']
175counters['gujaratinumerals'] = counters['gujarati']
176counters['tibetannumerals'] = counters['tibetan']
177counters['greeknumerals'] = counters['greek']
178counters['arabicnumerals'] = counters['arabic']
179counters['persiannumerals'] = counters['persian']
180counters['arabicexnumerals'] = counters['persian']
181counters['koreannumerals'] = counters['korean']
182counters['koreanparenthesisnumerals'] = counters['korean-parenthesis']
183counters['koreancirclenumerals'] = counters['korean-circle']
184
185counters['sloveniannumerals'] = counters['slovenian']
186counters['spanishnumerals'] = counters['spanish']
187counters['russiannumerals'] = counters['russian']
188
189local decimals = allocate {
190 ['arabic'] = {
191 ["0"] = "٠", ["1"] = "١", ["2"] = "٢", ["3"] = "٣", ["4"] = "٤",
192 ["5"] = "٥", ["6"] = "٦", ["7"] = "٧", ["8"] = "٨", ["9"] = "٩",
193 },
194 ['persian'] = {
195 ["0"] = "۰", ["1"] = "۱", ["2"] = "۲", ["3"] = "۳", ["4"] = "۴",
196 ["5"] = "۵", ["6"] = "۶", ["7"] = "۷", ["8"] = "۸", ["9"] = "۹",
197 },
198 ['devanagari'] = {
199 ["0"] = "०", ["1"] = "१", ["2"] = "२", ["3"] = "३", ["4"] = "४",
200 ["5"] = "५", ["6"] = "६", ["7"] = "७", ["8"] = "८", ["9"] = "९",
201 },
202 ['malayalam'] = {
203 ["0"] = "൦", ["1"] = "൧", ["2"] = "൨", ["3"] = "൩", ["4"] = "൪",
204 ["5"] = "൫", ["6"] = "൬", ["7"] = "൭", ["8"] = "൮", ["9"] = "൯",
205 },
206 ['tamil'] = {
207 ["0"] = "௦", ["1"] = "௧", ["2"] = "௨", ["3"] = "௩", ["4"] = "௪",
208 ["5"] = "௫", ["6"] = "௬", ["7"] = "௭", ["8"] = "௮", ["9"] = "௯",
209 },
210 ['kannada'] = {
211 ["0"] = "೦", ["1"] = "೧", ["2"] = "೨", ["3"] = "೩", ["4"] = "೪",
212 ["5"] = "೫", ["6"] = "೬", ["7"] = "೭", ["8"] = "೮", ["9"] = "೯",
213 },
214 ['telugu'] = {
215 ["0"] = "౦", ["1"] = "౧", ["2"] = "౨", ["3"] = "౩", ["4"] = "౪",
216 ["5"] = "౫", ["6"] = "౬", ["7"] = "౭", ["8"] = "౮", ["9"] = "౯",
217 },
218 ['bengali'] = {
219 ["0"] = "০", ["1"] = "১", ["2"] = "২", ["3"] = "৩", ["4"] = "৪",
220 ["5"] = "৫", ["6"] = "৬", ["7"] = "৭", ["8"] = "৮", ["9"] = "৯",
221 },
222 ['gujarati'] = {
223 ["0"] = "૦", ["1"] = "૧", ["2"] = "૨", ["3"] = "૩", ["4"] = "૪",
224 ["5"] = "૫", ["6"] = "૬", ["7"] = "૭", ["8"] = "૮", ["9"] = "૯",
225 },
226 ['gurmurkhi'] = {
227 ["0"] = "੦", ["1"] = "੧", ["2"] = "੨", ["3"] = "੩", ["4"] = "੪",
228 ["5"] = "੫", ["6"] = "੬", ["7"] = "੭", ["8"] = "੮", ["9"] = "੯",
229 },
230}
231
232languages.decimals = decimals
233
234local fallback = utfbyte('0')
235
236local function chr(n,m)
237 return (n > 0 and n < 27 and utfchar(n+m)) or ""
238end
239
240local function chrs(n,m,t)
241 if not t then
242 t = { }
243 end
244 if n > 26 then
245 chrs(floor((n-1)/26),m,t)
246 n = (n-1)%26 + 1
247 end
248 if n ~= 0 then
249 t[#t+1] = utfchar(n+m)
250 end
251 if n <= 26 then
252 return concat(t)
253 end
254end
255
256local function maxchrs(n,m,cmd,t)
257 if not t then
258 t = { }
259 end
260 if n > m then
261 maxchrs(floor((n-1)/m),m,cmd)
262 n = (n-1)%m + 1
263 end
264 t[#t+1] = formatters["%s{%s}"](cmd,n)
265 if n <= m then
266 return concat(t)
267 end
268end
269
270converters.chr = chr
271converters.chrs = chrs
272converters.maxchrs = maxchrs
273
274local lowercharacter = characters.lcchars
275local uppercharacter = characters.ucchars
276
277local defaultcounter = counters.default
278
279local function do_alphabetic(n,mapping,mapper,t)
280 if not t then
281 t = { }
282 end
283 local max = #mapping
284 if n > max then
285 do_alphabetic(floor((n-1)/max),mapping,mapper,t)
286 n = (n-1) % max + 1
287 end
288 local chr = mapping[n] or fallback
289 t[#t+1] = mapper and mapper[chr] or chr
290 if n <= max then
291 return concat(t)
292 end
293end
294
295local function alphabetic(n,code)
296 return do_alphabetic(n,code and code ~= "" and counters[code] or defaultcounter,lowercharacter)
297end
298
299local function Alphabetic(n,code)
300 return do_alphabetic(n,code and code ~= "" and counters[code] or defaultcounter,uppercharacter)
301end
302
303converters.alphabetic = alphabetic
304converters.Alphabetic = Alphabetic
305
306
307
308local function todecimals(n,name)
309 local stream = tostring(n)
310 local mapping = decimals[name]
311 return mapping and gsub(stream,".",mapping) or stream
312end
313
314converters.decimals = todecimals
315
316local lower_offset = 96
317local upper_offset = 64
318
319function converters.character (n) return chr (n,lower_offset) end
320function converters.Character (n) return chr (n,upper_offset) end
321function converters.characters(n) return chrs(n,lower_offset) end
322function converters.Characters(n) return chrs(n,upper_offset) end
323
324implement { name = "alphabetic", actions = { alphabetic, context }, arguments = { "integer", "string" } }
325implement { name = "Alphabetic", actions = { Alphabetic, context }, arguments = { "integer", "string" } }
326
327implement { name = "character", actions = { chr, context }, arguments = { "integer", lower_offset } }
328implement { name = "Character", actions = { chr, context }, arguments = { "integer", upper_offset } }
329implement { name = "characters", actions = { chrs, context }, arguments = { "integer", lower_offset } }
330implement { name = "Characters", actions = { chrs, context }, arguments = { "integer", upper_offset } }
331
332implement { name = "decimals", actions = { todecimals, context }, arguments = { "integer", "string" } }
333
334local weekday = os.weekday
335local isleapyear = os.isleapyear
336local nofdays = os.nofdays
337
338local function leapyear(year)
339 return isleapyear(year) and 1 or 0
340end
341
342local function textime()
343 return tonumber(osdate("%H")) * 60 + tonumber(osdate("%M"))
344end
345
346
347
348
349
350
351
352
353
354
355
356converters.weekday = weekday
357converters.isleapyear = isleapyear
358converters.leapyear = leapyear
359converters.nofdays = nofdays
360converters.textime = textime
361
362implement { name = "weekday", actions = { weekday, context }, arguments = { "integer", "integer", "integer" } }
363implement { name = "leapyear", actions = { leapyear, context }, arguments = "integer" }
364implement { name = "nofdays", actions = { nofdays, context }, arguments = { "integer", "integer" } }
365
366implement { name = "year", actions = { osdate, context }, arguments = "'%Y'" }
367implement { name = "month", actions = { osdate, context }, arguments = "'%m'" }
368implement { name = "day", actions = { osdate, context }, arguments = "'%d'" }
369implement { name = "hour", actions = { osdate, context }, arguments = "'%H'" }
370implement { name = "minute", actions = { osdate, context }, arguments = "'%M'" }
371implement { name = "second", actions = { osdate, context }, arguments = "'%S'" }
372implement { name = "textime", actions = { textime, context } }
373
374implement {
375 name = "doifelseleapyear",
376 actions = { isleapyear, commands.doifelse },
377 arguments = "integer"
378}
379
380local roman = {
381 { [0] = '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' },
382 { [0] = '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC' },
383 { [0] = '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM' },
384}
385
386local function toroman(n)
387 if n >= 4000 then
388 return toroman(floor(n/1000)) .. " " .. toroman(n%1000)
389 else
390 return rep("M",floor(n/1000)) .. roman[3][floor((n%1000)/100)] .. roman[2][floor((n%100)/10)] .. roman[1][floor((n%10)/1)]
391 end
392end
393
394converters.toroman = toroman
395converters.Romannumerals = toroman
396converters.romannumerals = function(n) return lower(toroman(n)) end
397
398converters['i'] = converters.romannumerals
399converters['I'] = converters.Romannumerals
400converters['r'] = converters.romannumerals
401converters['R'] = converters.Romannumerals
402converters['KR'] = converters.Romannumerals
403converters['RK'] = converters.Romannumerals
404
405implement {
406 name = "romannumerals",
407 actions = { toroman, lower, context },
408 arguments = "integer",
409}
410
411implement {
412 name = "Romannumerals",
413 actions = { toroman, context },
414 arguments = "integer",
415}
416
417
418
419
420
421
422
423
424
425
426
427
428local small = {
429 "ا", "ٮ", "ح", "د", "ه", "و", "ر",
430}
431
432local medium = {
433 "ا", "ب", "ج", "د", "ه", "و","ز", "ح", "ط" ,
434 "ي", "ك", "ل", "م", "ن", "س", "ع", "ف", "ص" ,
435 "ق", "ر", "ش", "ت", "ث", "خ", "ذ", "ض", "ظ" ,
436 "غ" ,
437}
438
439local large = {
440 { "ا", "ب", "ج", "د", "ه", "و","ز", "ح", "ط" },
441 { "ي", "ك", "ل", "م", "ن", "س", "ع", "ف", "ص" },
442 { "ق", "ر", "ش", "ت", "ث", "خ", "ذ", "ض", "ظ" },
443 { "غ" },
444}
445
446local function toabjad(n,what)
447 if n <= 0 or n >= 2000 then
448 return tostring(n)
449 elseif what == 2 and n <= 7 then
450 return small[n]
451 elseif what == 3 and n <= 28 then
452 return medium[n]
453 else
454 local a, b, c, d
455 a, n = floor(n/1000), n % 1000
456 b, n = floor(n/ 100), n % 100
457 c, n = floor(n/ 10), n % 10
458 d, n = floor(n/ 1), n % 1
459 return (large[4][a] or "") .. (large[3][b] or "") .. (large[2][c] or "") .. (large[1][d] or "")
460 end
461end
462
463converters.toabjad = toabjad
464
465function converters.abjadnumerals (n) return toabjad(n,false) end
466function converters.abjadnodotnumerals(n) return toabjad(n,true ) end
467
468implement {
469 name = "abjadnumerals",
470 actions = { toabjad, context },
471 arguments = { "integer", false }
472}
473
474implement {
475 name = "abjadnodotnumerals",
476 actions = { toabjad, context },
477 arguments = { "integer", true }
478}
479
480
481
482local trace_hebrew trackers.register("converters.hebrew", function(v)
483 trace_hebrew = v
484end)
485
486local list = {
487 { 400, "ת" }, { 300, "ש" }, { 200, "ר" }, { 100, "ק" },
488 { 90, "צ" }, { 80, "פ" }, { 70, "ע" }, { 60, "ס "}, { 50, "נ" }, { 40, "מ" }, { 30, "ל" }, { 20, "כ" }, { 10, "י" },
489 { 9, "ט" }, { 8, "ח" }, { 7, "ז", }, { 6, "ו", }, { 5, "ה" }, { 4, "ד" }, { 3, "ג" }, { 2, "ב" }, { 1, "א" },
490}
491
492local special = {
493 [15] = "ט״ו",
494 [16] = "ט״ז",
495}
496
497local function tohebrew(n,gershayim,geresh)
498 local split = { }
499 local size = 0
500 while n > 1000 do
501 size = size + 1
502 split[size] = n % 1000
503 n = floor(n/1000)
504 end
505 size = size + 1
506 split[size] = n
507 for i=1,size do
508 local t = { }
509 local n = 0
510 local s = split[i]
511 while s > 0 do
512 for i=1,#list do
513 ::again::
514 local li = list[i]
515 local l1 = li[1]
516 local s1 = special[l1]
517 if s1 then
518 s = s - l1
519 n = n + 1
520 t[n] = s1
521 goto again
522 elseif s >= l1 then
523 s = s - l1
524 n = n + 1
525 t[n] = li[2]
526 goto again
527 end
528 end
529 end
530 ::done::
531 split[i] = t
532 end
533 if gershayim then
534 for i=1,size do
535 local si = split[i]
536 local ni = #si
537 if ni >= 2 then
538 local s = "״"
539 insert(split[i],ni,trace_hebrew and ("{\\red "..s.."}") or s)
540 end
541 end
542 end
543 if geresh then
544 for i=2,#split do
545 local s = rep("׳",i-1)
546 insert(split[i],trace_hebrew and ("{\\blue "..s.."}") or s)
547 end
548 end
549 for i=1,size do
550 split[i] = concat(split[i])
551 end
552 return concat(reverse(split))
553end
554
555converters.tohebrew = tohebrew
556converters.hebrewnumerals = converters.tohebrew
557
558
559
560interfaces.implement {
561 name = "hebrewnumerals",
562 actions = { tohebrew, context },
563 arguments = { "integer", true, true }
564}
565
566
567
568local vector = {
569 normal = {
570 [0] = "〇",
571 [1] = "一",
572 [2] = "二",
573 [3] = "三",
574 [4] = "四",
575 [5] = "五",
576 [6] = "六",
577 [7] = "七",
578 [8] = "八",
579 [9] = "九",
580 [10] = "十",
581 [100] = "百",
582 [1000] = "千",
583 [10000] = "万",
584 [100000000] = "亿",
585 },
586 cap = {
587 [0] = "零",
588 [1] = "壹",
589 [2] = "贰",
590 [3] = "叁",
591 [4] = "肆",
592 [5] = "伍",
593 [6] = "陆",
594 [7] = "柒",
595 [8] = "捌",
596 [9] = "玖",
597 [10] = "拾",
598 [100] = "佰",
599 [1000] = "仟",
600 [10000] = "萬",
601 [100000000] = "亿",
602 },
603 all = {
604 [0] = "〇",
605 [1] = "一",
606 [2] = "二",
607 [3] = "三",
608 [4] = "四",
609 [5] = "五",
610 [6] = "六",
611 [7] = "七",
612 [8] = "八",
613 [9] = "九",
614 [10] = "十",
615 [20] = "廿",
616 [30] = "卅",
617 [100] = "百",
618 [1000] = "千",
619 [10000] = "万",
620 [100000000] = "亿",
621 }
622}
623
624local function tochinese(n,name)
625
626 local result, r = { }, 0
627
628 if name == "date" then
629
630
631
632 local vector = vector.normal
633 for s in gmatch(tostring(n),".") do
634 r = r + 1 ; result[r] = vector[tonumber(s)]
635 end
636 return concat(result)
637 end
638
639 local vector = vector[name] or vector.normal
640 while true do
641 if n == 0 then
642 break
643 elseif n >= 100000000 then
644 local m = floor(n/100000000)
645 r = r + 1 ; result[r] = tochinese(m,name)
646 r = r + 1 ; result[r] = vector[100000000]
647 local z = n - m * 100000000
648 if z > 0 and z < 10000000 then r = r + 1 ; result[r] = vector[0] end
649 n = n % 100000000
650 elseif n >= 10000000 then
651 local m = floor(n/10000)
652 r = r + 1 ; result[r] = tochinese(m,name)
653 r = r + 1 ; result[r] = vector[10000]
654 local z = n - m * 10000
655 if z > 0 and z < 1000 then r = r + 1 ; result[r] = vector[0] end
656 n = n % 10000
657 elseif n >= 1000000 then
658 local m = floor(n/10000)
659 r = r + 1 ; result[r] = tochinese(m,name)
660 r = r + 1 ; result[r] = vector[10000]
661 local z = n - m * 10000
662 if z > 0 and z < 1000 then r = r + 1 ; result[r] = vector[0] end
663 n = n % 10000
664 elseif n >= 100000 then
665 local m = floor(n/10000)
666 r = r + 1 ; result[r] = tochinese(m,name)
667 r = r + 1 ; result[r] = vector[10000]
668 local z = n - m * 10000
669 if z > 0 and z < 1000 then r = r + 1 ; result[r] = vector[0] end
670 n = n % 10000
671 elseif n >= 10000 then
672 local m = floor(n/10000)
673 r = r + 1 ; result[r] = vector[m]
674 r = r + 1 ; result[r] = vector[10000]
675 local z = n - m * 10000
676 if z > 0 and z < 1000 then r = r + 1 ; result[r] = vector[0] end
677 n = n % 10000
678 elseif n >= 1000 then
679 local m = floor(n/1000)
680 r = r + 1 ; result[r] = vector[m]
681 r = r + 1 ; result[r] = vector[1000]
682 local z = n - m * 1000
683 if z > 0 and z < 100 then r = r + 1 ; result[r] = vector[0] end
684 n = n % 1000
685 elseif n >= 100 then
686 local m = floor(n/100)
687 r = r + 1 ; result[r] = vector[m]
688 r = r + 1 ; result[r] = vector[100]
689 local z = n - m * 100
690 if z > 0 and z < 10 then r = r + 1 ; result[r] = vector[0] end
691 n = n % 100
692 elseif n >= 10 then
693 local m = floor(n/10)
694 if m > 1 and vector[m*10] then
695 r = r + 1 ; result[r] = vector[m*10]
696 else
697 r = r + 1 ; result[r] = vector[m]
698 r = r + 1 ; result[r] = vector[10]
699 end
700 n = n % 10
701 else
702 r = r + 1 ; result[r] = vector[n]
703 break
704 end
705 end
706 if (result[1] == vector[1] and result[2] == vector[10]) then
707 result[1] = ""
708 end
709 return concat(result)
710end
711
712
713
714
715
716
717
718converters.tochinese = tochinese
719
720function converters.chinesenumerals (n,how) return tochinese(n,how or "normal") end
721function converters.chinesecapnumerals(n) return tochinese(n,"cap") end
722function converters.chineseallnumerals(n) return tochinese(n,"all") end
723function converters.chinesedatenumerals(n) return tochinese(n,"date") end
724
725converters['cn'] = converters.chinesenumerals
726converters['cn-c'] = converters.chinesecapnumerals
727converters['cn-a'] = converters.chineseallnumerals
728converters['cn-d'] = converters.chinesedatenumerals
729
730implement {
731 name = "chinesenumerals",
732 actions = { tochinese, context },
733 arguments = { "integer", "string" }
734}
735
736
737
738
739converters['a'] = converters.characters
740converters['A'] = converters.Characters
741converters['AK'] = converters.Characters
742converters['KA'] = converters.Characters
743
744function converters.spanishnumerals (n) return alphabetic(n,"es") end
745function converters.Spanishnumerals (n) return Alphabetic(n,"es") end
746function converters.sloveniannumerals(n) return alphabetic(n,"sl") end
747function converters.Sloveniannumerals(n) return Alphabetic(n,"sl") end
748function converters.russiannumerals (n) return alphabetic(n,"ru") end
749function converters.Russiannumerals (n) return Alphabetic(n,"ru") end
750
751converters['alphabetic:es'] = converters.spanishnumerals
752converters['alphabetic:sl'] = converters.sloveniannumerals
753converters['alphabetic:ru'] = converters.russiannumerals
754
755converters['Alphabetic:es'] = converters.Spanishnumerals
756converters['Alphabetic:sl'] = converters.Sloveniannumerals
757converters['Alphabetic:ru'] = converters.Russiannumerals
758
759
760
761converters['a:es'] = converters.spanishnumerals
762converters['a:sl'] = converters.sloveniannumerals
763converters['a:ru'] = converters.russiannumerals
764converters['A:es'] = converters.Spanishnumerals
765converters['A:sl'] = converters.Sloveniannumerals
766converters['A:ru'] = converters.Russiannumerals
767
768
769
770converters.sequences = converters.sequences or { }
771local sequences = converters.sequences
772
773storage.register("converters/sequences", sequences, "converters.sequences")
774
775function converters.define(name,set)
776
777
778
779 sequences[name] = settings_to_array(set)
780end
781
782function converters.max(name)
783 local s = sequences[name]
784 return s and #s or 0
785end
786
787implement {
788 name = "defineconversion",
789 actions = converters.define,
790 arguments = "2 strings",
791}
792
793implement {
794 name = "nofconversions",
795 actions = { converters.max, context },
796 arguments = "string",
797}
798
799local function convert(method,n,language)
800 local converter = language and converters[method..":"..language] or converters[method]
801 if converter then
802 return converter(n)
803 else
804 local lowermethod = lower(method)
805 local linguistic = counters[lowermethod]
806 if linguistic then
807 return do_alphabetic(n,linguistic,lowermethod == method and lowercharacter or uppercharacter)
808 end
809 local sequence = sequences[method]
810 if sequence then
811 local max = #sequence
812 if n > max then
813 return sequence[(n-1) % max + 1]
814 else
815 return sequence[n]
816 end
817 end
818 return n
819 end
820end
821
822converters.convert = convert
823
824local function valid(method,language)
825 return converters[method..":"..language] or converters[method] or sequences[method]
826end
827
828implement {
829 name = "doifelseconverter",
830 actions = { valid, commands.doifelse },
831 arguments = "2 strings",
832}
833
834implement {
835 name = "checkedconversion",
836 actions = { convert, context },
837 arguments = { "string", "integer" }
838}
839
840
841
842local gregorian_to_hebrew do
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860 local NISAN = 1
861 local IYYAR = 2
862 local SIVAN = 3
863 local TAMUZ = 4
864 local AV = 5
865 local ELUL = 6
866 local TISHREI = 7
867 local CHESHVAN = 8
868 local KISLEV = 9
869 local TEVET = 10
870 local SHVAT = 11
871 local ADAR_I = 12
872 local ADAR_II = 13
873
874 local mmap = {
875 KISLEV,
876 TEVET,
877 SHVAT,
878 ADAR_I,
879 NISAN,
880 IYYAR,
881 SIVAN,
882 TAMUZ,
883 TISHREI,
884 TISHREI,
885 TISHREI,
886 CHESHVAN
887 }
888
889 local function greg2abs(year,month,day)
890 local y = year - 1
891 return y * 365 + div(y,4)- div(y,100) + div(y,400) + os.nofdays(year,month,day)
892 end
893
894 local function abs2greg(abs)
895
896 local d0 = abs - 1
897
898 local n400 = div(d0, 146097)
899 local d1 = mod(d0, 146097)
900 local n100 = div(d1, 36524)
901 local d2 = mod(d1, 36524)
902 local n4 = div(d2, 1461)
903 local d3 = mod(d2, 1461)
904 local n1 = div(d3, 365)
905
906 local day = mod(d3, 365) + 1
907 local year = 400 * n400 + 100 * n100 + 4 * n4 + n1
908
909 if n100 == 4 or n1 == 4 then
910 return year, 12, 31
911 else
912 year = year + 1
913 month = 1
914 while true do
915 local mlen = os.nofdays(year,month)
916 if mlen < day then
917 day = day - mlen
918 month = month + 1
919 else
920 break
921 end
922 end
923 return year, month, day
924 end
925 end
926
927 local function hebrew_leapyear(year)
928 return mod(1 + year * 7, 19) < 7
929 end
930
931 local function hebrew_months_in_year(year)
932 return hebrew_leapyear(year) and 13 or 12
933 end
934
935 local function hebrew_elapsed_days(year)
936 local y = year - 1
937 local m_elapsed = 235 * div(y,19) + 12 * mod(y,19) + div(((mod(y,19) * 7) + 1),19)
938 local p_elapsed = 204 + 793 * mod(m_elapsed,1080)
939 local h_elapsed = 5 + 12 * m_elapsed + 793 * div(m_elapsed,1080) + div(p_elapsed,1080)
940 local parts = mod(p_elapsed,1080) + 1080 * mod(h_elapsed,24)
941 local day = 1 + 29 * m_elapsed + div(h_elapsed,24)
942 local d = mod(day,7)
943 local alt_day = day
944 if parts >= 19440
945 or (parts >= 9924 and d == 2 and not (hebrew_leapyear(year)))
946 or (parts >= 16789 and d == 1 and hebrew_leapyear(y )) then
947 alt_day = alt_day + 1
948 end
949 d = mod(alt_day,7)
950 if d == 0 or d == 3 or d == 5 then
951 alt_day = alt_day + 1
952 end
953 return alt_day
954 end
955
956 local function days_in_hebrew_year(year)
957 return hebrew_elapsed_days(year + 1) - hebrew_elapsed_days(year)
958 end
959
960 local function long_cheshvan(year)
961 return mod(days_in_hebrew_year(year),10) == 5
962 end
963
964 local function short_kislev(year)
965 return mod(days_in_hebrew_year(year),10) == 3
966 end
967
968 local function max_days_in_heb_month(month,year)
969 if month == IYYAR or month == TAMUZ or month == ELUL or month == TEVET or month == ADAR_II or
970 (month == ADAR_I and not hebrew_leapyear(year)) or
971 (month == CHESHVAN and not long_cheshvan(year)) or
972 (month == KISLEV and short_kislev (year)) then
973 return 29
974 else
975 return 30
976 end
977 end
978
979 local function hebrew2abs(year,month,day)
980 if month < TISHREI then
981 for m=TISHREI, hebrew_months_in_year(year), 1 do
982 day = day + max_days_in_heb_month(m,year)
983 end
984 for m=NISAN, month - 1, 1 do
985 day = day + max_days_in_heb_month(m,year)
986 end
987 else
988 for m=TISHREI, month - 1, 1 do
989 day = day + max_days_in_heb_month(m,year)
990 end
991 end
992 return hebrew_elapsed_days(year) - 1373429 + day
993 end
994
995 local function abs2hebrew(abs)
996 local yy, mm, dd = abs2greg(abs)
997 local day = 1
998 local month = TISHREI
999 local year = 3760 + yy
1000 while abs >= hebrew2abs(year+1,month,day) do
1001 year = year + 1
1002 end
1003 if year >= 4635 and year < 10666 then
1004 month = mmap[mm]
1005 end
1006 while abs > hebrew2abs(year,month,max_days_in_heb_month(month,year)) do
1007 month = mod(month,hebrew_months_in_year(year)) + 1
1008 end
1009 day = abs - hebrew2abs(year,month,1) + 1
1010 return year, month, day
1011 end
1012
1013
1014
1015 gregorian_to_hebrew = function(y,m,d)
1016 return abs2hebrew(greg2abs(y,m,d))
1017 end
1018
1019 converters.gregorian_to_hebrew = gregorian_to_hebrew
1020
1021end
1022
1023local gregorian_to_jalali, jalali_to_gregorian do
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037 local g_days_in_month = { [0] = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
1038 local j_days_in_month = { [0] = 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
1039
1040
1041 gregorian_to_jalali = function(gy,gm,gd)
1042 local jy, jm, jd, g_day_no, j_day_no, j_np, i
1043 gy, gm, gd = gy - 1600, gm - 1, gd - 1
1044 g_day_no = 365*gy + div((gy+3),4) - div((gy+99),100) + div((gy+399),400)
1045 i = 0
1046 while i < gm do
1047 g_day_no = g_day_no + g_days_in_month[i]
1048 i = i + 1
1049 end
1050 if (gm>1 and ((gy%4==0 and gy%100~=0) or (gy%400==0))) then
1051 g_day_no = g_day_no + 1
1052 end
1053 g_day_no = g_day_no + gd
1054 j_day_no = g_day_no - 79
1055 j_np = div(j_day_no,12053)
1056 j_day_no = mod(j_day_no,12053)
1057 jy = 979 + 33*j_np + 4*div(j_day_no,1461)
1058 j_day_no = mod(j_day_no,1461)
1059 if j_day_no >= 366 then
1060 jy = jy + div((j_day_no-1),365)
1061 j_day_no = mod((j_day_no-1),365)
1062 end
1063 i = 0
1064 while i < 11 and j_day_no >= j_days_in_month[i] do
1065 j_day_no = j_day_no - j_days_in_month[i]
1066 i = i + 1
1067 end
1068 jm = i + 1
1069 jd = j_day_no + 1
1070 return jy, jm, jd
1071 end
1072
1073 jalali_to_gregorian = function(jy,jm,jd)
1074 local gy, gm, gd, g_day_no, j_day_no, leap, i
1075 jy, jm, jd = jy - 979, jm - 1, jd - 1
1076 j_day_no = 365*jy + div(jy,33)*8 + div((mod(jy,33)+3),4)
1077 for i=0,jm-1,1 do
1078 j_day_no = j_day_no + j_days_in_month[i]
1079 end
1080 j_day_no = j_day_no + jd
1081 g_day_no = j_day_no + 79
1082 gy = 1600 + 400*div(g_day_no,146097)
1083 g_day_no = mod(g_day_no, 146097)
1084 leap = 1
1085 if g_day_no >= 36525 then
1086 g_day_no = g_day_no - 1
1087 gy = gy + 100*div(g_day_no,36524)
1088 g_day_no = mod(g_day_no, 36524)
1089 if g_day_no >= 365 then
1090 g_day_no = g_day_no + 1
1091 else
1092 leap = 0
1093 end
1094 end
1095 gy = gy + 4*div(g_day_no,1461)
1096 g_day_no = mod(g_day_no, 1461)
1097 if g_day_no >= 366 then
1098 leap = 0
1099 g_day_no = g_day_no - 1
1100 gy = gy + div(g_day_no, 365)
1101 g_day_no = mod(g_day_no, 365)
1102 end
1103 i = 0
1104 while true do
1105 local d = g_days_in_month[i] + ((i == 1 and leap) or 0)
1106 if g_day_no >= d then
1107 g_day_no = g_day_no - d
1108 i = i + 1
1109 else
1110 break
1111 end
1112 end
1113 gm = i + 1
1114 gd = g_day_no + 1
1115 return gy, gm, gd
1116 end
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133 converters.gregorian_to_jalali = gregorian_to_jalali
1134 converters.jalali_to_gregorian = jalali_to_gregorian
1135
1136end
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174local ordinals = {
1175 english = function(n)
1176 local two = n % 100
1177 if two == 11 or two == 12 or two == 13 then
1178 return "th"
1179 else
1180 local one = n % 10
1181 if one == 1 then
1182 return "st"
1183 elseif one == 2 then
1184 return "nd"
1185 elseif one == 3 then
1186 return "rd"
1187 else
1188 return "th"
1189 end
1190 end
1191 end,
1192 dutch = function(n)
1193 return "e"
1194 end,
1195 french = function(n)
1196 if n == 1 then
1197 return "er"
1198 else
1199 return "e"
1200 end
1201 end,
1202}
1203
1204ordinals.en = ordinals.english
1205ordinals.nl = ordinals.dutch
1206ordinals.fr = ordinals.french
1207
1208function converters.ordinal(n,language)
1209 local t = language and ordinals[language]
1210 return t and t(n)
1211end
1212
1213local function ctxordinal(n,language)
1214 local t = language and ordinals[language]
1215 local o = t and t(n)
1216 context(n)
1217 if o then
1218 ctx_highordinalstr(o)
1219 end
1220end
1221
1222implement {
1223 name = "ordinal",
1224 actions = ctxordinal,
1225 arguments = { "integer", "string" }
1226}
1227
1228
1229
1230local data = allocate()
1231local verbose = { data = data }
1232converters.verbose = verbose
1233
1234
1235
1236local words = {
1237 [0] = "zero",
1238 [1] = "one",
1239 [2] = "two",
1240 [3] = "three",
1241 [4] = "four",
1242 [5] = "five",
1243 [6] = "six",
1244 [7] = "seven",
1245 [8] = "eight",
1246 [9] = "nine",
1247 [10] = "ten",
1248 [11] = "eleven",
1249 [12] = "twelve",
1250 [13] = "thirteen",
1251 [14] = "fourteen",
1252 [15] = "fifteen",
1253 [16] = "sixteen",
1254 [17] = "seventeen",
1255 [18] = "eighteen",
1256 [19] = "nineteen",
1257 [20] = "twenty",
1258 [30] = "thirty",
1259 [40] = "forty",
1260 [50] = "fifty",
1261 [60] = "sixty",
1262 [70] = "seventy",
1263 [80] = "eighty",
1264 [90] = "ninety",
1265 [100] = "hundred",
1266 [1000] = "thousand",
1267 [1000000] = "million",
1268 [1000000000] = "billion",
1269 [1000000000000] = "trillion",
1270}
1271
1272local function translate(n,connector)
1273 local w = words[n]
1274 if w then
1275 return w
1276 end
1277 local t = { }
1278 local function compose_one(n)
1279 local w = words[n]
1280 if w then
1281 t[#t+1] = w
1282 return
1283 end
1284 local a, b = floor(n/100), n % 100
1285 if a == 10 then
1286 t[#t+1] = words[1]
1287 t[#t+1] = words[1000]
1288 elseif a > 0 then
1289 t[#t+1] = words[a]
1290 t[#t+1] = words[100]
1291
1292 if b == 0 then
1293 return
1294 end
1295 end
1296 if words[b] then
1297 t[#t+1] = words[b]
1298 else
1299 a, b = floor(b/10), n % 10
1300 t[#t+1] = words[a*10]
1301 t[#t+1] = words[b]
1302 end
1303 end
1304 local function compose_two(n,m)
1305 if n > (m-1) then
1306 local a, b = floor(n/m), n % m
1307 if a > 0 then
1308 compose_one(a)
1309 end
1310 t[#t+1] = words[m]
1311 n = b
1312 end
1313 return n
1314 end
1315 n = compose_two(n,1000000000000)
1316 n = compose_two(n,1000000000)
1317 n = compose_two(n,1000000)
1318 n = compose_two(n,1000)
1319 if n > 0 then
1320 compose_one(n)
1321 end
1322 return #t > 0 and concat(t,connector or " ") or tostring(n)
1323end
1324
1325data.english = {
1326 words = words,
1327 translate = translate,
1328}
1329
1330data.en = data.english
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342local words = {
1343 [1] = "uno",
1344 [2] = "dos",
1345 [3] = "tres",
1346 [4] = "cuatro",
1347 [5] = "cinco",
1348 [6] = "seis",
1349 [7] = "siete",
1350 [8] = "ocho",
1351 [9] = "nueve",
1352 [10] = "diez",
1353 [11] = "once",
1354 [12] = "doce",
1355 [13] = "trece",
1356 [14] = "catorce",
1357 [15] = "quince",
1358 [16] = "dieciséis",
1359 [17] = "diecisiete",
1360 [18] = "dieciocho",
1361 [19] = "diecinueve",
1362 [20] = "veinte",
1363 [21] = "veintiuno",
1364 [22] = "veintidós",
1365 [23] = "veintitrés",
1366 [24] = "veinticuatro",
1367 [25] = "veinticinco",
1368 [26] = "veintiséis",
1369 [27] = "veintisiete",
1370 [28] = "veintiocho",
1371 [29] = "veintinueve",
1372 [30] = "treinta",
1373 [40] = "cuarenta",
1374 [50] = "cincuenta",
1375 [60] = "sesenta",
1376 [70] = "setenta",
1377 [80] = "ochenta",
1378 [90] = "noventa",
1379 [100] = "ciento",
1380 [200] = "doscientos",
1381 [300] = "trescientos",
1382 [400] = "cuatrocientos",
1383 [500] = "quinientos",
1384 [600] = "seiscientos",
1385 [700] = "setecientos",
1386 [800] = "ochocientos",
1387 [900] = "novecientos",
1388 [1000] = "mil",
1389 [1000000] = "millón",
1390 [1000000000] = "mil millones",
1391 [1000000000000] = "billón",
1392}
1393
1394local function translate(n,connector)
1395 local w = words[n]
1396 if w then
1397 return w
1398 end
1399 local t = { }
1400 local function compose_one(n)
1401 local w = words[n]
1402 if w then
1403 t[#t+1] = w
1404 return
1405 end
1406
1407 local a, b = floor(n/100), n % 100
1408
1409 if a == 10 then
1410 t[#t+1] = words[1]
1411 t[#t+1] = words[1000]
1412
1413
1414
1415 elseif a > 0 then
1416 t[#t+1] = words[a*100]
1417 end
1418
1419 if words[b] then
1420 t[#t+1] = words[b]
1421 else
1422
1423 a, b = floor(b/10), n % 10
1424 t[#t+1] = words[a*10]
1425 t[#t+1] = "y"
1426 t[#t+1] = words[b]
1427 end
1428 end
1429
1430
1431 local function compose_two(n,m)
1432 if n > (m-1) then
1433 local a, b = floor(n/m), n % m
1434 if a > 0 then
1435 compose_one(a)
1436 end
1437 t[#t+1] = words[m]
1438 n = b
1439 end
1440 return n
1441 end
1442 n = compose_two(n,1000000000000)
1443 n = compose_two(n,1000000000)
1444 n = compose_two(n,1000000)
1445 n = compose_two(n,1000)
1446 if n > 0 then
1447 compose_one(n)
1448 end
1449 return #t > 0 and concat(t,connector or " ") or tostring(n)
1450end
1451
1452data.spanish = {
1453 words = words,
1454 translate = translate,
1455}
1456
1457data.es = data.spanish
1458
1459
1460
1461
1462
1463
1464
1465do
1466
1467 local words = {
1468 [0] = "noll",
1469 [1] = "ett",
1470 [2] = "två",
1471 [3] = "tre",
1472 [4] = "fyra",
1473 [5] = "fem",
1474 [6] = "sex",
1475 [7] = "sju",
1476 [8] = "åtta",
1477 [9] = "nio",
1478 [10] = "tio",
1479 [11] = "elva",
1480 [12] = "tolv",
1481 [13] = "tretton",
1482 [14] = "fjorton",
1483 [15] = "femton",
1484 [16] = "sexton",
1485 [17] = "sjutton",
1486 [18] = "arton",
1487 [19] = "nitton",
1488 [20] = "tjugo",
1489 [30] = "trettio",
1490 [40] = "fyrtio",
1491 [50] = "femtio",
1492 [60] = "sextio",
1493 [70] = "sjuttio",
1494 [80] = "åttio",
1495 [90] = "nittio",
1496 [100] = "hundra",
1497 [10^3] = "tusen",
1498 [10^6] = "miljon",
1499 [10^9] = "miljard",
1500 [10^12] = "biljon",
1501 [10^15] = "biljard",
1502 }
1503
1504 local function translate(n,connector)
1505 local w = words[n]
1506 if w then
1507 return w
1508 else
1509 local t = { }
1510 local l = 0
1511
1512 local function triplets(n)
1513 if floor(n/100) > 0 then
1514 l = l + 1 ; t[l] = words[floor(n/100)]
1515 l = l + 1 ; t[l] = words[100]
1516 end
1517 if n%100 > 20 then
1518 l = l + 1 ; t[l] = words[n%100-n%10]
1519 if n%10 > 0 then
1520 l = l + 1 ; t[l] = words[n%10]
1521 end
1522 elseif n%100 > 0 then
1523 l = l + 1 ; t[l] = words[n%100]
1524 end
1525 end
1526
1527
1528 for i=15,3,-3 do
1529 local triplet = floor(n/10^i)%10^3
1530 if triplet > 0 then
1531
1532 if i > 3 and triplet == 1 then
1533 l = l + 1 ; t[l] = "en"
1534 else
1535 triplets(triplet)
1536 end
1537
1538 l = l + 1 ; t[l] = words[10^i]
1539 if i > 3 and triplet > 1 then
1540 l = l + 1 ; t[l] = "er"
1541 end
1542 end
1543 end
1544
1545 n = n%1000
1546 if n > 0 then
1547 triplets(n)
1548 end
1549 t = concat(t," ")
1550
1551 if n < 10^6 then
1552 t = gsub(t,"%stusen%s","tusen")
1553 t = gsub(t,"etttusen","ettusen")
1554 end
1555 return t
1556 end
1557 end
1558
1559 data.swedish = {
1560 words = words,
1561 translate = translate,
1562 }
1563
1564 data.sv = data.swedish
1565
1566end
1567
1568
1569
1570function converters.verbose.translate(n,language,connector)
1571 local t = language and data[language]
1572 return t and t.translate(n,connector) or n
1573end
1574
1575local function verbose(n,language,connector)
1576 local t = language and data[language]
1577 context(t and t.translate(n,connector) or n)
1578end
1579
1580implement {
1581 name = "verbose",
1582 actions = verbose,
1583 arguments = { "integer", "string", "string" }
1584}
1585
1586
1587
1588
1589local whitespace = lpegpatterns.whitespace
1590local word = lpegpatterns.utf8uppercharacter^-1 * (1-whitespace)^1
1591local pattern_one = Cs( whitespace^0 * word^-1 * P(1)^0)
1592local pattern_all = Cs((whitespace^1 + word)^1)
1593
1594function converters.word (s) return s end
1595function converters.words(s) return s end
1596
1597local function Word (s) return lpegmatch(pattern_one,s) or s end
1598local function Words(s) return lpegmatch(pattern_all,s) or s end
1599
1600converters.Word = Word
1601converters.Words = Words
1602
1603converters.upper = characters.upper
1604converters.lower = characters.lower
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618local v_day = variables.day
1619local v_year = variables.year
1620local v_month = variables.month
1621local v_weekday = variables.weekday
1622local v_referral = variables.referral
1623local v_space = variables.space
1624
1625local v_MONTH = upper(v_month)
1626local v_WEEKDAY = upper(v_weekday)
1627
1628local convert = converters.convert
1629
1630local days = {
1631 "sunday",
1632 "monday",
1633 "tuesday",
1634 "wednesday",
1635 "thursday",
1636 "friday",
1637 "saturday",
1638}
1639
1640local months = {
1641 "january",
1642 "february",
1643 "march",
1644 "april",
1645 "may",
1646 "june",
1647 "july",
1648 "august",
1649 "september",
1650 "october",
1651 "november",
1652 "december",
1653}
1654
1655local monthmnems = {
1656
1657}
1658
1659local daymnems = {
1660
1661}
1662
1663setmetatableindex(days, function(t,k) return "unknown" end)
1664setmetatableindex(daymnems, function(t,k) return days[k] .. ":mnem" end)
1665setmetatableindex(months, function(t,k) return "unknown" end)
1666setmetatableindex(monthmnems, function(t,k) return months[k] .. ":mnem" end)
1667
1668do
1669
1670 local function dayname(n)
1671 ctx_labeltext(days[n])
1672 end
1673
1674 local function daymnem(n)
1675 ctx_labeltext(daymnems[n])
1676 end
1677
1678 local function weekdayname(day,month,year)
1679 ctx_labeltext(days[weekday(day,month,year)])
1680 end
1681
1682 local function monthname(n)
1683 ctx_labeltext(months[n])
1684 end
1685
1686 local function monthmnem(n)
1687 ctx_labeltext(monthmnems[n])
1688 end
1689
1690 implement {
1691 name = "dayname",
1692 actions = dayname,
1693 arguments = "integer",
1694 }
1695
1696 implement {
1697 name = "daymnem",
1698 actions = daymnem,
1699 arguments = "integer",
1700 }
1701
1702 implement {
1703 name = "weekdayname",
1704 actions = weekdayname,
1705 arguments = { "integer", "integer", "integer" }
1706 }
1707
1708 implement {
1709 name = "monthname",
1710 actions = monthname,
1711 arguments = "integer",
1712 }
1713
1714 implement {
1715 name = "monthmnem",
1716 actions = monthmnem,
1717 arguments = "integer",
1718 }
1719
1720
1721
1722 local f_monthlong = formatters["\\monthlong{%s}"]
1723 local f_monthshort = formatters["\\monthshort{%s}"]
1724 local f_daylong = formatters["\\daylong{%s}"]
1725 local f_dayshort = formatters["\\dayshort{%s}"]
1726 local f_weekday = formatters["\\weekday{%s}"]
1727 local f_dayoftheweek = formatters["\\dayoftheweek{%s}{%s}{%s}"]
1728
1729 local function tomonthlong (m) return f_monthlong (tonumber(m) or 1) end
1730 local function tomonthshort(m) return f_monthshort(tonumber(m) or 1) end
1731 local function todaylong (d) return f_daylong (tonumber(d) or 1) end
1732 local function todayshort (d) return f_dayshort (tonumber(d) or 1) end
1733 local function toweekday (d) return f_weekday (tonumber(d) or 1) end
1734
1735 local function todayoftheweek(d,m,y)
1736 return f_dayoftheweek(tonumber(d) or 1,tonumber(m) or 1,tonumber(y) or 2000)
1737 end
1738
1739 addformatter(formatters,"monthlong", [[tomonthlong(%s)]], { tomonthlong = tomonthlong })
1740 addformatter(formatters,"monthshort", [[tomonthshort(%s)]], { tomonthshort = tomonthshort })
1741 addformatter(formatters,"daylong", [[todaylong(%s)]], { todaylong = todaylong })
1742 addformatter(formatters,"dayshort", [[todayshort(%s)]], { todayshort = todayshort })
1743 addformatter(formatters,"weekday", [[toweekday(%s)]], { toweekday = toweekday })
1744 addformatter(formatters,"dayoftheweek",[[todayoftheweek(%s,%s,%s)]],{ todayoftheweek = todayoftheweek })
1745
1746
1747
1748 local function toeyear (e) return osdate("%Y",tonumber(e)) end
1749 local function toemonth (e) return osdate("%m",tonumber(e)) end
1750 local function toeday (e) return osdate("%d",tonumber(e)) end
1751 local function toeminute(e) return osdate("%M",tonumber(e)) end
1752 local function toesecond(e) return osdate("%S",tonumber(e)) end
1753
1754 local function toemonthlong(e)
1755 return f_monthlong(tonumber(osdate("%m",tonumber(e))))
1756 end
1757
1758 local function toemonthshort(e)
1759 return f_monthshort(tonumber(osdate("%m",tonumber(e))))
1760 end
1761
1762 local function toedaylong(e)
1763 return f_datlong(tonumber(osdate("%w",tonumber(e))))
1764 end
1765
1766 local function toedayshort(e)
1767 return f_dayshort(tonumber(osdate("%w",tonumber(e))))
1768 end
1769
1770 local function toeweek(e)
1771 return tostring(tonumber(osdate("%w",tonumber(e)))+1)
1772 end
1773
1774 local function toeweekday(e)
1775 return f_weekday(tonumber(osdate("%w",tonumber(e)))+1)
1776 end
1777
1778 local function toedate(format,e)
1779 return osdate(format,tonumber(e))
1780 end
1781
1782 addformatter(formatters,"eyear", [[toeyear(%s)]], { toeyear = toeyear })
1783 addformatter(formatters,"emonth", [[toemonth(%s)]], { toemonth = toemonth })
1784 addformatter(formatters,"eday", [[toeday(%s)]], { toeday = toeday })
1785 addformatter(formatters,"eweek", [[toeweek(%s)]], { toeweek = toeweek })
1786 addformatter(formatters,"eminute", [[toeminute(%s)]], { toeminute = toeminute })
1787 addformatter(formatters,"esecond", [[toesecond(%s)]], { toesecond = toesecond })
1788
1789 addformatter(formatters,"emonthlong", [[toemonthlong(%s)]], { toemonthlong = toemonthlong })
1790 addformatter(formatters,"emonthshort", [[toemonthshort(%s)]], { toemonthshort = toemonthshort })
1791 addformatter(formatters,"edaylong", [[toedaylong(%s)]], { toedaylong = toedaylong })
1792 addformatter(formatters,"edayshort", [[toedayshort(%s)]], { toedayshort = toedayshort })
1793 addformatter(formatters,"eweekday", [[toeweekday(%s)]], { toeweekday = toeweekday })
1794
1795 addformatter(formatters,"edate", [[toedate(%s,%s)]], { toedate = toedate })
1796
1797end
1798
1799
1800
1801
1802
1803
1804local spaced = {
1805 [v_year] = true,
1806 [v_month] = true,
1807 [v_MONTH] = true,
1808 [v_day] = true,
1809 [v_weekday] = true,
1810 [v_WEEKDAY] = true,
1811}
1812
1813local dateconverters = {
1814 ["hebrew:to"] = gregorian_to_hebrew,
1815 ["jalali:to"] = gregorian_to_jalali,
1816 ["jalali:from"] = jalali_to_gregorian,
1817}
1818
1819local variants = {
1820 mnem = {
1821 month = monthmnems,
1822 day = daymnems,
1823 },
1824 hebrew = {
1825 month = setmetatableindex(function(t,k) return months[k] .. ":hebrew" end),
1826 day = setmetatableindex(function(t,k) return days [k] .. ":hebrew" end),
1827 },
1828 jalali = {
1829 month = setmetatableindex(function(t,k) return months[k] .. ":jalali" end),
1830 day = setmetatableindex(function(t,k) return days [k] .. ":jalali" end),
1831 },
1832}
1833
1834do
1835
1836 local function currentdate(str,currentlanguage,year,month,day)
1837 local list = utilities.parsers.settings_to_array(str)
1838 local splitlabel = languages.labels.split or string.itself
1839
1840
1841
1842 local auto = true
1843 if currentlanguage == "" then
1844 currentlanguage = false
1845 end
1846 for i=1,#list do
1847 local entry = list[i]
1848 local convert = dateconverters[entry]
1849 if convert then
1850 year, month, day = convert(year,month,day)
1851 else
1852 local tag, plus = splitlabel(entry)
1853 local ordinal, mnemonic, whatordinal, highordinal = false, false, nil, false
1854 if not tag then
1855 tag = entry
1856 elseif plus == "+" or plus == "ord" then
1857 ordinal = true
1858 elseif plus == "++" or plus == "highord" then
1859 ordinal = true
1860 highordinal = true
1861 elseif plus then
1862 mnemonic = variants[plus]
1863 end
1864 if not auto and spaced[tag] then
1865 ctx_space()
1866 end
1867 auto = false
1868 if tag == v_year or tag == "y" or tag == "Y" then
1869 if plus then
1870 plus = converters[plus]
1871 end
1872 if plus then
1873 context(plus(year))
1874 elseif currentlanguage == false then
1875 context(year)
1876 else
1877 ctx_convertnumber(v_year,year)
1878 end
1879 elseif tag == "yy" or tag == "YY" then
1880 context("%02i",year % 100)
1881 elseif tag == v_month or tag == "m" then
1882 if currentlanguage == false then
1883 context(Word(months[month]))
1884 else
1885 if type(mnemonic) == "table" then
1886 mnemonic = mnemonic.month
1887 end
1888 if mnemonic then
1889 ctx_labeltext(variables[mnemonic[month]])
1890 else
1891 ctx_labeltext(variables[months[month]])
1892 end
1893 end
1894 elseif tag == v_MONTH then
1895 if currentlanguage == false then
1896 context(Word(variables[months[month]]))
1897 else
1898 if type(mnemonic) == "table" then
1899 mnemonic = mnemonic.month
1900 end
1901 if mnemonic then
1902 ctx_LABELTEXT(variables[mnemonic[month]])
1903 else
1904 ctx_LABELTEXT(variables[months[month]])
1905 end
1906 end
1907 elseif tag == "mm" then
1908 context("%02i",month)
1909 elseif tag == "M" then
1910 context(month)
1911 elseif tag == v_day or tag == "d" then
1912 if plus then
1913 plus = converters[plus]
1914 end
1915 if plus then
1916 context(plus(day))
1917 elseif currentlanguage == false then
1918 context(day)
1919 else
1920 ctx_convertnumber(v_day,day)
1921 end
1922 whatordinal = day
1923 elseif tag == "dd" then
1924 context("%02i",day)
1925 whatordinal = day
1926 elseif tag == "D" then
1927 context(day)
1928 whatordinal = day
1929 elseif tag == v_weekday or tag == "w" then
1930 local wd = weekday(day,month,year)
1931 if currentlanguage == false then
1932 context(Word(days[wd]))
1933 else
1934 if type(mnemonic) == "table" then
1935 mnemonic = mnemonic.day
1936 end
1937 if mnemonic then
1938 ctx_labeltext(variables[mnemonic[wd]])
1939 else
1940 ctx_labeltext(variables[days[wd]])
1941 end
1942 end
1943 elseif tag == v_WEEKDAY then
1944 local wd = weekday(day,month,year)
1945 if currentlanguage == false then
1946 context(Word(days[wd]))
1947 else
1948 if type(mnemonic) == "table" then
1949 mnemonic = mnemonic.day
1950 end
1951 if mnemonic then
1952 ctx_LABELTEXT(variables[mnemonic[wd]])
1953 else
1954 ctx_LABELTEXT(variables[days[wd]])
1955 end
1956 end
1957 elseif tag == "W" then
1958 context(weekday(day,month,year))
1959 elseif tag == v_referral then
1960 context("%04i%02i%02i",year,month,day)
1961 elseif tag == v_space or tag == "\\ " then
1962 ctx_space()
1963 auto = true
1964 elseif tag ~= "" then
1965 context(tag)
1966 auto = true
1967 end
1968 if ordinal and whatordinal then
1969 if currentlanguage == false then
1970
1971 else
1972 context[highordinal and "highordinalstr" or "ordinalstr"](converters.ordinal(whatordinal,currentlanguage))
1973 end
1974 end
1975 end
1976 end
1977 end
1978
1979 implement {
1980 name = "currentdate",
1981 arguments = { "string", "string", "string", "integer", "integer", "integer" },
1982 actions = function(pattern,default,language,year,month,day)
1983 currentdate(
1984 pattern == "" and default or pattern,
1985 language == "" and false or language,
1986 year, month, day
1987 )
1988 end,
1989 }
1990
1991 local function todate(s,y,m,d)
1992 if y or m or d then
1993 return formatters["\\date[y=%s,m=%s,d=%s][%s]\\relax"](y or "",m or "",d or "",s or "")
1994 else
1995 return formatters["\\currentdate[%s]\\relax"](s)
1996 end
1997 end
1998
1999 addformatter(formatters,"date", [[todate(...)]], { todate = todate })
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009end
2010
2011implement {
2012 name = "unihex",
2013 arguments = "integer",
2014 actions = { formatters["U+%05X"], context },
2015}
2016
2017
2018
2019local n = R("09")^1 / tonumber
2020
2021local p = Cf( Ct("")
2022
2023 * Cg(Cc("year") * n)
2024 * S("-/")^-1
2025 * Cg(Cc("month") * (n + Cc(1)))
2026 * S("-/")^-1
2027 * Cg(Cc("day") * (n + Cc(1)))
2028
2029 * (
2030 whitespace^0
2031 * P("T")^-1
2032 * whitespace^0
2033 * Cg(Cc("hour") * n)
2034 * P(":")^-1
2035 * Cg(Cc("min") * n)
2036 * P(":")^-1
2037 * Cg(Cc("sec") * (n + Cc(0)))
2038 )^-1
2039
2040 * (
2041 whitespace^0
2042 * Cg(Cc("tzs") * (P("+") * Cc(1) + P("-") * Cc(-1) + Cc(1)))
2043 * whitespace^0
2044 * Cg(Cc("tzh") * n)
2045 * P(":")^-1
2046 * Cg(Cc("tzm") * (n + Cc(0)))
2047 )^-1
2048 , rawset)
2049
2050function converters.totime(s)
2051 if not s then
2052 return
2053 elseif type(s) == "table" then
2054 return s
2055 elseif type(s) == "string" then
2056 local t = lpegmatch(p,s)
2057 if not t then
2058 logs.report("system","invalid time specification %a",s)
2059 elseif t.tzh then
2060 local localtzh, localtzm = ostimezone(true)
2061 t.hour = t.hour + localtzh - t.tzs * t.tzh
2062 t.min = t.min + localtzm - t.tzs * t.tzm
2063 end
2064 return t
2065 end
2066 local n = tonumber(s)
2067 if n and n >= 0 then
2068 return osdate("*t",n)
2069 end
2070end
2071
2072function converters.settime(t)
2073 if type(t) ~= "table" then
2074 t = converters.totime(t)
2075 end
2076 if t then
2077 texset("year", t.year or 1000)
2078 texset("month", t.month or 1)
2079 texset("day", t.day or 1)
2080 texset("time", (t.hour or 0) * 60 + (t.min or 0))
2081 end
2082end
2083
2084
2085
2086local d_one = lpegpatterns.digit
2087local d_two = d_one * d_one
2088local d_three = d_two * d_one
2089local d_four = d_three * d_one
2090local d_split = P(-1) + Carg(2) * (lpegpatterns.period /"")
2091
2092local d_spaced = (Carg(1) * d_three)^1
2093
2094local digitized_1 = Cs ( (
2095 d_three * d_spaced * d_split +
2096 d_two * d_spaced * d_split +
2097 d_one * d_spaced * d_split +
2098 P(1)
2099 )^1 )
2100
2101local p_fourbefore = d_four * d_split
2102local p_fourafter = d_four * P(-1)
2103
2104local p_beforesplit = d_three * d_spaced^0 * d_split
2105 + d_two * d_spaced^0 * d_split
2106 + d_one * d_spaced^0 * d_split
2107 + d_one * d_split
2108
2109local p_aftersplit = p_fourafter
2110 + d_three * d_spaced
2111 + d_two * d_spaced
2112 + d_one * d_spaced
2113
2114local digitized_2 = Cs (
2115 p_fourbefore * (p_aftersplit^0) +
2116 p_beforesplit * ((p_aftersplit + d_one^1)^0)
2117 )
2118
2119local p_fourbefore = d_four * d_split
2120local p_fourafter = d_four
2121local d_spaced = (Carg(1) * (d_three + d_two + d_one))^1
2122local p_aftersplit = p_fourafter * P(-1)
2123 + d_three * d_spaced * P(1)^0
2124 + d_one^1
2125
2126local digitized_3 = Cs((p_fourbefore + p_beforesplit) * p_aftersplit^0)
2127
2128local digits_space = utfchar(0x2008)
2129
2130local splitmethods = {
2131 digitized_1,
2132 digitized_2,
2133 digitized_3,
2134}
2135
2136local replacers = table.setmetatableindex(function(t,k)
2137 local v = lpeg.replacer(".",k)
2138 t[k] = v
2139 return v
2140end)
2141
2142function converters.spaceddigits(settings,data)
2143 local data = tostring(data or settings.data or "")
2144 if data ~= "" then
2145 local method = settings.method
2146 local split = splitmethods[tonumber(method) or 1]
2147 if split then
2148 local symbol = settings.symbol
2149 local separator = settings.separator
2150 if not symbol or symbol == "" then
2151 symbol = "."
2152 end
2153 if type(separator) ~= "string" or separator == "" then
2154 separator = digits_space
2155 end
2156 local result = lpegmatch(split,data,1,separator,symbol)
2157 if not result and symbol ~= "." then
2158 result = lpegmatch(replacers[symbol],data)
2159 end
2160 if result then
2161
2162 return result
2163 end
2164 end
2165 end
2166 return str
2167end
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209implement {
2210 name = "spaceddigits",
2211 actions = { converters.spaceddigits, context },
2212 arguments = {
2213 {
2214 { "symbol" },
2215 { "separator" },
2216 { "data" },
2217 { "method" },
2218 }
2219 }
2220}
2221
2222local function field(n) return context(osdate("*t")[n]) end
2223
2224implement { name = "actualday", public = true, actions = function() field("day") end }
2225implement { name = "actualmonth", public = true, actions = function() field("month") end }
2226implement { name = "actualyear", public = true, actions = function() field("year") end }
2227
2228implement {
2229 name = "uuid",
2230 public = true,
2231 actions = { os.uuid, context },
2232}
2233 |