• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 9304049654

30 May 2024 02:12PM UTC coverage: 60.021% (-14.7%) from 74.707%
9304049654

push

github

web-flow
Merge 1a26b4f22 into a1fd105f8

6743 of 12900 new or added lines in 186 files covered. (52.27%)

347 existing lines in 49 files now uncovered.

10311 of 17179 relevant lines covered (60.02%)

3307.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

26.76
/languages/tr.lua
1
-- Different years of TDK and various publisher style guides differ on this point.
2
-- Current official guidance suggests dropping the hypenation mark if the break
3
-- occurs at an apostrophe (kesme işareti). Some older guidance and some publishers
4
-- suggest dropping the apostrophe instead.
5
SILE.settings:declare({
3✔
6
   parameter = "languages.tr.replaceApostropheAtHyphenation",
7
   type = "boolean",
8
   default = false,
9
   help = "If enabled, substitute the apostophe for a hyphen at break points, otherwise keep the apostrophe and hide the hyphen.",
10
})
11

12
-- Quotes may be part of a word in Turkish
13
SILE.nodeMakers.tr = pl.class(SILE.nodeMakers.unicode)
6✔
14
SILE.nodeMakers.tr.wordTypes = { cm = true, qu = true }
3✔
15

16
SILE.hyphenator.languages["tr"] = {}
3✔
17

18
SILE.hyphenator.languages["tr"].hyphenateSegments = function (node, segments, j)
3✔
19
   local hyphenChar, replacement
20
   local maybeNextApostrophe = #segments > j and luautf8.match(segments[j + 1], "^['’]")
24✔
21
   if maybeNextApostrophe then
24✔
22
      segments[j + 1] = luautf8.gsub(segments[j + 1], "^['’]", "")
4✔
23
      if SILE.settings:get("languages.tr.replaceApostropheAtHyphenation") then
8✔
24
         hyphenChar = SILE.settings:get("font.hyphenchar")
2✔
25
      else
26
         hyphenChar = maybeNextApostrophe
3✔
27
         replacement = SILE.shaper:createNnodes(maybeNextApostrophe, node.options)
6✔
28
      end
29
   else
30
      hyphenChar = SILE.settings:get("font.hyphenchar")
40✔
31
   end
32
   local hyphen = SILE.shaper:createNnodes(hyphenChar, node.options)
24✔
33
   return SILE.types.node.discretionary({ replacement = replacement, prebreak = hyphen }), segments
48✔
34
end
35

36
SILE.hyphenator.languages["tr"].patterns = {
3✔
37
   "2a1",
38
   "2â1",
39
   "2e1",
40
   "2ı1",
41
   "2i1",
42
   "2î1",
43
   "2o1",
44
   "2ö1",
45
   "2u1",
46
   "2ü1",
47
   "2û1",
48
   -- allow hyphen either side of consonants
49
   "1b1",
50
   "1c1",
51
   "1ç1",
52
   "1d1",
53
   "1f1",
54
   "1g1",
55
   "1ğ1",
56
   "1h1",
57
   "1j1",
58
   "1k1",
59
   "1l1",
60
   "1m1",
61
   "1n1",
62
   "1p1",
63
   "1r1",
64
   "1s1",
65
   "1ş1",
66
   "1t1",
67
   "1v1",
68
   "1y1",
69
   "1z1",
70
   -- prevent a-cak/e-cek at end of word
71
   "2a2cak.",
72
   "2e2cek.",
73
   -- prohibit hyphen before pair of consonants
74
   -- many pairs generated here are impossible anyway
75
   "2bb",
76
   "2bc",
77
   "2bç",
78
   "2bd",
79
   "2bf",
80
   "2bg",
81
   "2bğ",
82
   "2bh",
83
   "2bj",
84
   "2bk",
85
   "2bl",
86
   "2bm",
87
   "2bn",
88
   "2bp",
89
   "2br",
90
   "2bs",
91
   "2bş",
92
   "2bt",
93
   "2bv",
94
   "2by",
95
   "2bz",
96
   "2cb",
97
   "2cc",
98
   "2cç",
99
   "2cd",
100
   "2cf",
101
   "2cg",
102
   "2cğ",
103
   "2ch",
104
   "2cj",
105
   "2ck",
106
   "2cl",
107
   "2cm",
108
   "2cn",
109
   "2cp",
110
   "2cr",
111
   "2cs",
112
   "2cş",
113
   "2ct",
114
   "2cv",
115
   "2cy",
116
   "2cz",
117
   "2çb",
118
   "2çc",
119
   "2çç",
120
   "2çd",
121
   "2çf",
122
   "2çg",
123
   "2çğ",
124
   "2çh",
125
   "2çj",
126
   "2çk",
127
   "2çl",
128
   "2çm",
129
   "2çn",
130
   "2çp",
131
   "2çr",
132
   "2çs",
133
   "2çş",
134
   "2çt",
135
   "2çv",
136
   "2çy",
137
   "2çz",
138
   "2db",
139
   "2dc",
140
   "2dç",
141
   "2dd",
142
   "2df",
143
   "2dg",
144
   "2dğ",
145
   "2dh",
146
   "2dj",
147
   "2dk",
148
   "2dl",
149
   "2dm",
150
   "2dn",
151
   "2dp",
152
   "2dr",
153
   "2ds",
154
   "2dş",
155
   "2dt",
156
   "2dv",
157
   "2dy",
158
   "2dz",
159
   "2fb",
160
   "2fc",
161
   "2fç",
162
   "2fd",
163
   "2ff",
164
   "2fg",
165
   "2fğ",
166
   "2fh",
167
   "2fj",
168
   "2fk",
169
   "2fl",
170
   "2fm",
171
   "2fn",
172
   "2fp",
173
   "2fr",
174
   "2fs",
175
   "2fş",
176
   "2ft",
177
   "2fv",
178
   "2fy",
179
   "2fz",
180
   "2gb",
181
   "2gc",
182
   "2gç",
183
   "2gd",
184
   "2gf",
185
   "2gg",
186
   "2gğ",
187
   "2gh",
188
   "2gj",
189
   "2gk",
190
   "2gl",
191
   "2gm",
192
   "2gn",
193
   "2gp",
194
   "2gr",
195
   "2gs",
196
   "2gş",
197
   "2gt",
198
   "2gv",
199
   "2gy",
200
   "2gz",
201
   "2ğb",
202
   "2ğc",
203
   "2ğç",
204
   "2ğd",
205
   "2ğf",
206
   "2ğg",
207
   "2ğğ",
208
   "2ğh",
209
   "2ğj",
210
   "2ğk",
211
   "2ğl",
212
   "2ğm",
213
   "2ğn",
214
   "2ğp",
215
   "2ğr",
216
   "2ğs",
217
   "2ğş",
218
   "2ğt",
219
   "2ğv",
220
   "2ğy",
221
   "2ğz",
222
   "2hb",
223
   "2hc",
224
   "2hç",
225
   "2hd",
226
   "2hf",
227
   "2hg",
228
   "2hğ",
229
   "2hh",
230
   "2hj",
231
   "2hk",
232
   "2hl",
233
   "2hm",
234
   "2hn",
235
   "2hp",
236
   "2hr",
237
   "2hs",
238
   "2hş",
239
   "2ht",
240
   "2hv",
241
   "2hy",
242
   "2hz",
243
   "2jb",
244
   "2jc",
245
   "2jç",
246
   "2jd",
247
   "2jf",
248
   "2jg",
249
   "2jğ",
250
   "2jh",
251
   "2jj",
252
   "2jk",
253
   "2jl",
254
   "2jm",
255
   "2jn",
256
   "2jp",
257
   "2jr",
258
   "2js",
259
   "2jş",
260
   "2jt",
261
   "2jv",
262
   "2jy",
263
   "2jz",
264
   "2kb",
265
   "2kc",
266
   "2kç",
267
   "2kd",
268
   "2kf",
269
   "2kg",
270
   "2kğ",
271
   "2kh",
272
   "2kj",
273
   "2kk",
274
   "2kl",
275
   "2km",
276
   "2kn",
277
   "2kp",
278
   "2kr",
279
   "2ks",
280
   "2kş",
281
   "2kt",
282
   "2kv",
283
   "2ky",
284
   "2kz",
285
   "2lb",
286
   "2lc",
287
   "2lç",
288
   "2ld",
289
   "2lf",
290
   "2lg",
291
   "2lğ",
292
   "2lh",
293
   "2lj",
294
   "2lk",
295
   "2ll",
296
   "2lm",
297
   "2ln",
298
   "2lp",
299
   "2lr",
300
   "2ls",
301
   "2lş",
302
   "2lt",
303
   "2lv",
304
   "2ly",
305
   "2lz",
306
   "2mb",
307
   "2mc",
308
   "2mç",
309
   "2md",
310
   "2mf",
311
   "2mg",
312
   "2mğ",
313
   "2mh",
314
   "2mj",
315
   "2mk",
316
   "2ml",
317
   "2mm",
318
   "2mn",
319
   "2mp",
320
   "2mr",
321
   "2ms",
322
   "2mş",
323
   "2mt",
324
   "2mv",
325
   "2my",
326
   "2mz",
327
   "2nb",
328
   "2nc",
329
   "2nç",
330
   "2nd",
331
   "2nf",
332
   "2ng",
333
   "2nğ",
334
   "2nh",
335
   "2nj",
336
   "2nk",
337
   "2nl",
338
   "2nm",
339
   "2nn",
340
   "2np",
341
   "2nr",
342
   "2ns",
343
   "2nş",
344
   "2nt",
345
   "2nv",
346
   "2ny",
347
   "2nz",
348
   "2pb",
349
   "2pc",
350
   "2pç",
351
   "2pd",
352
   "2pf",
353
   "2pg",
354
   "2pğ",
355
   "2ph",
356
   "2pj",
357
   "2pk",
358
   "2pl",
359
   "2pm",
360
   "2pn",
361
   "2pp",
362
   "2pr",
363
   "2ps",
364
   "2pş",
365
   "2pt",
366
   "2pv",
367
   "2py",
368
   "2pz",
369
   "2rb",
370
   "2rc",
371
   "2rç",
372
   "2rd",
373
   "2rf",
374
   "2rg",
375
   "2rğ",
376
   "2rh",
377
   "2rj",
378
   "2rk",
379
   "2rl",
380
   "2rm",
381
   "2rn",
382
   "2rp",
383
   "2rr",
384
   "2rs",
385
   "2rş",
386
   "2rt",
387
   "2rv",
388
   "2ry",
389
   "2rz",
390
   "2sb",
391
   "2sc",
392
   "2sç",
393
   "2sd",
394
   "2sf",
395
   "2sg",
396
   "2sğ",
397
   "2sh",
398
   "2sj",
399
   "2sk",
400
   "2sl",
401
   "2sm",
402
   "2sn",
403
   "2sp",
404
   "2sr",
405
   "2ss",
406
   "2sş",
407
   "2st",
408
   "2sv",
409
   "2sy",
410
   "2sz",
411
   "2şb",
412
   "2şc",
413
   "2şç",
414
   "2şd",
415
   "2şf",
416
   "2şg",
417
   "2şğ",
418
   "2şh",
419
   "2şj",
420
   "2şk",
421
   "2şl",
422
   "2şm",
423
   "2şn",
424
   "2şp",
425
   "2şr",
426
   "2şs",
427
   "2şş",
428
   "2şt",
429
   "2şv",
430
   "2şy",
431
   "2şz",
432
   "2tb",
433
   "2tc",
434
   "2tç",
435
   "2td",
436
   "2tf",
437
   "2tg",
438
   "2tğ",
439
   "2th",
440
   "2tj",
441
   "2tk",
442
   "2tl",
443
   "2tm",
444
   "2tn",
445
   "2tp",
446
   "2tr",
447
   "2ts",
448
   "2tş",
449
   "2tt",
450
   "2tv",
451
   "2ty",
452
   "2tz",
453
   "2vb",
454
   "2vc",
455
   "2vç",
456
   "2vd",
457
   "2vf",
458
   "2vg",
459
   "2vğ",
460
   "2vh",
461
   "2vj",
462
   "2vk",
463
   "2vl",
464
   "2vm",
465
   "2vn",
466
   "2vp",
467
   "2vr",
468
   "2vs",
469
   "2vş",
470
   "2vt",
471
   "2vv",
472
   "2vy",
473
   "2vz",
474
   "2yb",
475
   "2yc",
476
   "2yç",
477
   "2yd",
478
   "2yf",
479
   "2yg",
480
   "2yğ",
481
   "2yh",
482
   "2yj",
483
   "2yk",
484
   "2yl",
485
   "2ym",
486
   "2yn",
487
   "2yp",
488
   "2yr",
489
   "2ys",
490
   "2yş",
491
   "2yt",
492
   "2yv",
493
   "2yy",
494
   "2yz",
495
   "2zb",
496
   "2zc",
497
   "2zç",
498
   "2zd",
499
   "2zf",
500
   "2zg",
501
   "2zğ",
502
   "2zh",
503
   "2zj",
504
   "2zk",
505
   "2zl",
506
   "2zm",
507
   "2zn",
508
   "2zp",
509
   "2zr",
510
   "2zs",
511
   "2zş",
512
   "2zt",
513
   "2zv",
514
   "2zy",
515
   "2zz",
516
   -- allow hyphen between vowels, but not after second vowel of pair
517
   -- several phonetically impossible pairs here
518
   "a3a2",
519
   "a3â2",
520
   "a3e2",
521
   "a3ı2",
522
   "a3i2",
523
   "a3î2",
524
   "a3o2",
525
   "a3ö2",
526
   "a3u2",
527
   "a3ü2",
528
   "a3û2",
529
   "â3a2",
530
   "â3â2",
531
   "â3e2",
532
   "â3ı2",
533
   "â3i2",
534
   "â3î2",
535
   "â3o2",
536
   "â3ö2",
537
   "â3u2",
538
   "â3ü2",
539
   "â3û2",
540
   "e3a2",
541
   "e3â2",
542
   "e3e2",
543
   "e3ı2",
544
   "e3i2",
545
   "e3î2",
546
   "e3o2",
547
   "e3ö2",
548
   "e3u2",
549
   "e3ü2",
550
   "e3û2",
551
   "ı3a2",
552
   "ı3â2",
553
   "ı3e2",
554
   "ı3ı2",
555
   "ı3i2",
556
   "ı3î2",
557
   "ı3o2",
558
   "ı3ö2",
559
   "ı3u2",
560
   "ı3ü2",
561
   "ı3û2",
562
   "i3a2",
563
   "i3â2",
564
   "i3e2",
565
   "i3ı2",
566
   "i3i2",
567
   "i3î2",
568
   "i3o2",
569
   "i3ö2",
570
   "i3u2",
571
   "i3ü2",
572
   "i3û2",
573
   "î3a2",
574
   "î3â2",
575
   "î3e2",
576
   "î3ı2",
577
   "î3i2",
578
   "î3î2",
579
   "î3o2",
580
   "î3ö2",
581
   "î3u2",
582
   "î3ü2",
583
   "î3û2",
584
   "o3a2",
585
   "o3â2",
586
   "o3e2",
587
   "o3ı2",
588
   "o3i2",
589
   "o3î2",
590
   "o3o2",
591
   "o3ö2",
592
   "o3u2",
593
   "o3ü2",
594
   "o3û2",
595
   "ö3a2",
596
   "ö3â2",
597
   "ö3e2",
598
   "ö3ı2",
599
   "ö3i2",
600
   "ö3î2",
601
   "ö3o2",
602
   "ö3ö2",
603
   "ö3u2",
604
   "ö3ü2",
605
   "ö3û2",
606
   "u3a2",
607
   "u3â2",
608
   "u3e2",
609
   "u3ı2",
610
   "u3i2",
611
   "u3î2",
612
   "u3o2",
613
   "u3ö2",
614
   "u3u2",
615
   "u3ü2",
616
   "u3û2",
617
   "ü3a2",
618
   "ü3â2",
619
   "ü3e2",
620
   "ü3ı2",
621
   "ü3i2",
622
   "ü3î2",
623
   "ü3o2",
624
   "ü3ö2",
625
   "ü3u2",
626
   "ü3ü2",
627
   "ü3û2",
628
   "û3a2",
629
   "û3â2",
630
   "û3e2",
631
   "û3ı2",
632
   "û3i2",
633
   "û3î2",
634
   "û3o2",
635
   "û3ö2",
636
   "û3u2",
637
   "û3ü2",
638
   "û3û2",
639
   -- a couple of consonant-clusters
640
   "tu4r4k",
641
   "m1t4rak",
642
   -- See https://github.com/sile-typesetter/sile/issues/355
643
   -- Allow hyphenation to apply before apostrophes (before per pattern rules but
644
   -- will be substututed later, allowing after breaks minright), but work around
645
   -- minleft not being applied mid-word by excluding all possible single letter
646
   -- candidates before apostrophes.
647
   "1'2",
648
   "1’2",
649
   "4a1'",
650
   "4a1’",
651
   "4â1'",
652
   "4â1’",
653
   "4b1'",
654
   "4b1’",
655
   "4c1'",
656
   "4c1’",
657
   "4ç1'",
658
   "4ç1’",
659
   "4d1'",
660
   "4d1’",
661
   "4e1'",
662
   "4e1’",
663
   "4f1'",
664
   "4f1’",
665
   "4g1'",
666
   "4g1’",
667
   "4ğ1'",
668
   "4ğ1’",
669
   "4h1'",
670
   "4h1’",
671
   "4j1'",
672
   "4j1’",
673
   "4k1'",
674
   "4k1’",
675
   "4ı1'",
676
   "4ı1’",
677
   "4i1'",
678
   "4i1’",
679
   "4î1'",
680
   "4î1’",
681
   "4l1'",
682
   "4l1’",
683
   "4m1'",
684
   "4m1’",
685
   "4n1'",
686
   "4n1’",
687
   "4o1'",
688
   "4o1’",
689
   "4ö1'",
690
   "4ö1’",
691
   "4p1'",
692
   "4p1’",
693
   "4r1'",
694
   "4r1’",
695
   "4s1'",
696
   "4s1’",
697
   "4ş1'",
698
   "4ş1’",
699
   "4t1'",
700
   "4t1’",
701
   "4u1'",
702
   "4u1’",
703
   "4ü1'",
704
   "4ü1’",
705
   "4û1'",
706
   "4û1’",
707
   "4v1'",
708
   "4v1’",
709
   "4y1'",
710
   "4y1’",
711
   "4z1'",
712
   "4z1’",
713
}
1✔
714

715
-- Internationalisation stuff
716

717
-- local sum_tens = function (val, loc, digits)
718
--   local ten = string.sub(digits, loc+1, loc+1)
719
--   if ten:len() == 1 then val = val + tonumber(ten) * 10 end
720
--   return val
721
-- end
722

723
local sum_hundreds = function (val, loc, digits)
NEW
724
   local ten = string.sub(digits, loc + 1, loc + 1)
×
NEW
725
   local hundred = string.sub(digits, loc + 2, loc + 2)
×
NEW
726
   if ten:len() == 1 then
×
NEW
727
      val = val + tonumber(ten) * 10
×
728
   end
NEW
729
   if hundred:len() == 1 then
×
NEW
730
      val = val + tonumber(hundred) * 100
×
731
   end
NEW
732
   return val
×
733
end
734

735
local tr_nums = function (num, ordinal)
NEW
736
   local abs = math.abs(num)
×
NEW
737
   if abs >= 1e+36 then
×
NEW
738
      SU.error("Numbers past decillions not supported in Turkish")
×
739
   end
NEW
740
   ordinal = SU.boolean(ordinal, false)
×
NEW
741
   local minus = "eksi"
×
NEW
742
   local zero = "sıfır"
×
NEW
743
   local ones = { "bir", "iki", "üç", "dört", "beş", "altı", "yedi", "sekiz", "dokuz" }
×
NEW
744
   local tens = { "on", "yirmi", "otuz", "kırk", "eli", "altmış", "yetmiş", "seksen", "doksan" }
×
NEW
745
   local places = {
×
746
      "yüz",
747
      "bin",
748
      "milyon",
749
      "milyar",
750
      "trilyon",
751
      "katrilyon",
752
      "kentilyon",
753
      "sekstilyon",
754
      "septilyon",
755
      "oktilyon",
756
      "nonilyon",
757
      "desilyon",
758
   }
NEW
759
   local zeroordinal = "sıfırıncı"
×
760
   local onesordinals =
NEW
761
      { "birinci", "ikinci", "üçüncü", "dördüncü", "beşinci", "altıncı", "yedinci", "sekizinci", "dokuzuncu" }
×
NEW
762
   local tensordinals = {
×
763
      "onuncu",
764
      "yirmiyinci",
765
      "otuzuncu",
766
      "kırkıncı",
767
      "eliyinci",
768
      "altmışıncı",
769
      "yetmişinci",
770
      "sekseninci",
771
      "Doksanıncı",
772
   }
NEW
773
   local placesordinals = {
×
774
      "yüzüncü",
775
      "bininci",
776
      "milyonuncu",
777
      "milyarıncı",
778
      "trilyonuncu",
779
      "katrilyonuncu",
780
      "kentilyonuncu",
781
      "sekstilyonuncu",
782
      "septilyonuncu",
783
      "oktilyonuncu",
784
      "nonilyonuncu",
785
      "desilyonuncu",
786
   }
NEW
787
   local digits = string.reverse(string.format("%.f", abs))
×
NEW
788
   local words = {}
×
NEW
789
   for i = 1, #digits do
×
NEW
790
      local val, place, mod = tonumber(string.sub(digits, i, i)), math.floor(i / 3), i % 3
×
NEW
791
      if #digits == 1 and val == 0 then
×
NEW
792
         words[#words + 1] = ordinal and zeroordinal or zero
×
NEW
793
      elseif val >= 1 or i > 1 then
×
NEW
794
         if i == 1 then
×
NEW
795
            words[#words + 1] = ordinal and onesordinals[val] or ones[val]
×
NEW
796
            ordinal = false
×
NEW
797
         elseif mod == 2 then
×
NEW
798
            if val >= 1 then
×
NEW
799
               words[#words + 1] = ordinal and tensordinals[val] or tens[val]
×
NEW
800
               ordinal = false
×
801
            end
NEW
802
         elseif mod == 1 then
×
NEW
803
            if sum_hundreds(val, i, digits) >= 1 then
×
NEW
804
               words[#words + 1] = ordinal and placesordinals[place + 1] or places[place + 1]
×
NEW
805
               ordinal = false
×
NEW
806
               if val > 0 and (i >= 7 or sum_hundreds(val, i, digits) >= 2) then
×
NEW
807
                  words[#words + 1] = ones[val]
×
808
               end
809
            end
NEW
810
         elseif mod == 0 then
×
NEW
811
            if val > 0 then
×
NEW
812
               words[#words + 1] = ordinal and placesordinals[1] or places[1]
×
NEW
813
               ordinal = false
×
814
            end
NEW
815
            if val >= 2 then
×
NEW
816
               words[#words + 1] = ones[val]
×
817
            end
818
         end
819
      end
820
   end
NEW
821
   if abs > num then
×
NEW
822
      words[#words + 1] = minus
×
823
   end
NEW
824
   SU.flip_in_place(words)
×
NEW
825
   return table.concat(words, " ")
×
826
end
827

828
SU.formatNumber.tr = {
1✔
829
   string = function (num, _)
NEW
830
      return tr_nums(num, false)
×
831
   end,
832
   ["ordinal-string"] = function (num, _)
NEW
833
      return tr_nums(num, true)
×
834
   end,
835
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc