twitter_cldr 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (280) hide show
  1. data/Gemfile +3 -2
  2. data/History.txt +7 -1
  3. data/README.md +55 -0
  4. data/lib/twitter_cldr/core_ext.rb +1 -1
  5. data/lib/twitter_cldr/formatters/list_formatter.rb +64 -0
  6. data/lib/twitter_cldr/formatters.rb +4 -2
  7. data/lib/twitter_cldr/localized/localized_array.rb +19 -1
  8. data/lib/twitter_cldr/localized/localized_hash.rb +20 -0
  9. data/lib/twitter_cldr/localized/localized_string.rb +46 -1
  10. data/lib/twitter_cldr/localized/localized_symbol.rb +4 -0
  11. data/lib/twitter_cldr/localized.rb +1 -0
  12. data/lib/twitter_cldr/resources/bidi_test_importer.rb +118 -0
  13. data/lib/twitter_cldr/resources/locales_resources_importer.rb +1 -1
  14. data/lib/twitter_cldr/resources.rb +1 -0
  15. data/lib/twitter_cldr/shared/bidi.rb +526 -0
  16. data/lib/twitter_cldr/shared/languages.rb +5 -0
  17. data/lib/twitter_cldr/shared.rb +1 -0
  18. data/lib/twitter_cldr/utils/code_points.rb +1 -1
  19. data/lib/twitter_cldr/utils/yaml.rb +390 -0
  20. data/lib/twitter_cldr/utils.rb +1 -0
  21. data/lib/twitter_cldr/version.rb +1 -1
  22. data/lib/twitter_cldr.rb +2 -0
  23. data/resources/custom/locales/en/units.yml +19 -18
  24. data/resources/locales/af/calendars.yml +67 -66
  25. data/resources/locales/af/languages.yml +22 -22
  26. data/resources/locales/af/layout.yml +5 -0
  27. data/resources/locales/af/lists.yml +7 -0
  28. data/resources/locales/af/numbers.yml +36 -36
  29. data/resources/locales/af/plurals.yml +2 -3
  30. data/resources/locales/af/units.yml +75 -75
  31. data/resources/locales/ar/calendars.yml +149 -148
  32. data/resources/locales/ar/languages.yml +501 -501
  33. data/resources/locales/ar/layout.yml +5 -0
  34. data/resources/locales/ar/lists.yml +7 -0
  35. data/resources/locales/ar/numbers.yml +31 -31
  36. data/resources/locales/ar/plurals.yml +2 -9
  37. data/resources/locales/ar/units.yml +220 -220
  38. data/resources/locales/ca/calendars.yml +78 -77
  39. data/resources/locales/ca/languages.yml +199 -199
  40. data/resources/locales/ca/layout.yml +5 -0
  41. data/resources/locales/ca/lists.yml +7 -0
  42. data/resources/locales/ca/numbers.yml +36 -36
  43. data/resources/locales/ca/plurals.yml +2 -3
  44. data/resources/locales/ca/units.yml +108 -108
  45. data/resources/locales/cs/calendars.yml +141 -140
  46. data/resources/locales/cs/languages.yml +399 -399
  47. data/resources/locales/cs/layout.yml +5 -0
  48. data/resources/locales/cs/lists.yml +7 -0
  49. data/resources/locales/cs/numbers.yml +41 -41
  50. data/resources/locales/cs/plurals.yml +2 -3
  51. data/resources/locales/cs/units.yml +142 -142
  52. data/resources/locales/da/calendars.yml +73 -73
  53. data/resources/locales/da/languages.yml +36 -36
  54. data/resources/locales/da/layout.yml +5 -0
  55. data/resources/locales/da/lists.yml +7 -0
  56. data/resources/locales/da/numbers.yml +37 -37
  57. data/resources/locales/da/plurals.yml +2 -3
  58. data/resources/locales/da/units.yml +97 -97
  59. data/resources/locales/de/calendars.yml +71 -71
  60. data/resources/locales/de/languages.yml +51 -51
  61. data/resources/locales/de/layout.yml +5 -0
  62. data/resources/locales/de/lists.yml +7 -0
  63. data/resources/locales/de/numbers.yml +36 -36
  64. data/resources/locales/de/plurals.yml +2 -3
  65. data/resources/locales/de/units.yml +108 -108
  66. data/resources/locales/el/calendars.yml +213 -212
  67. data/resources/locales/el/languages.yml +520 -520
  68. data/resources/locales/el/layout.yml +5 -0
  69. data/resources/locales/el/lists.yml +7 -0
  70. data/resources/locales/el/numbers.yml +39 -39
  71. data/resources/locales/el/plurals.yml +2 -3
  72. data/resources/locales/el/units.yml +143 -143
  73. data/resources/locales/en/calendars.yml +66 -65
  74. data/resources/locales/en/languages.yml +24 -24
  75. data/resources/locales/en/layout.yml +5 -0
  76. data/resources/locales/en/lists.yml +7 -0
  77. data/resources/locales/en/numbers.yml +27 -27
  78. data/resources/locales/en/plurals.yml +2 -3
  79. data/resources/locales/en/units.yml +94 -94
  80. data/resources/locales/es/calendars.yml +80 -79
  81. data/resources/locales/es/languages.yml +139 -139
  82. data/resources/locales/es/layout.yml +5 -0
  83. data/resources/locales/es/lists.yml +7 -0
  84. data/resources/locales/es/numbers.yml +36 -36
  85. data/resources/locales/es/plurals.yml +2 -3
  86. data/resources/locales/es/units.yml +96 -96
  87. data/resources/locales/eu/calendars.yml +68 -67
  88. data/resources/locales/eu/languages.yml +11 -11
  89. data/resources/locales/eu/layout.yml +5 -0
  90. data/resources/locales/eu/lists.yml +7 -0
  91. data/resources/locales/eu/numbers.yml +36 -36
  92. data/resources/locales/eu/plurals.yml +2 -3
  93. data/resources/locales/eu/units.yml +80 -80
  94. data/resources/locales/fa/calendars.yml +223 -222
  95. data/resources/locales/fa/languages.yml +489 -489
  96. data/resources/locales/fa/layout.yml +5 -0
  97. data/resources/locales/fa/lists.yml +7 -0
  98. data/resources/locales/fa/numbers.yml +26 -26
  99. data/resources/locales/fa/plurals.yml +2 -3
  100. data/resources/locales/fa/units.yml +122 -122
  101. data/resources/locales/fi/calendars.yml +87 -87
  102. data/resources/locales/fi/languages.yml +86 -86
  103. data/resources/locales/fi/layout.yml +5 -0
  104. data/resources/locales/fi/lists.yml +7 -0
  105. data/resources/locales/fi/numbers.yml +41 -41
  106. data/resources/locales/fi/plurals.yml +2 -3
  107. data/resources/locales/fi/units.yml +124 -124
  108. data/resources/locales/fil/calendars.yml +68 -67
  109. data/resources/locales/fil/languages.yml +19 -19
  110. data/resources/locales/fil/layout.yml +5 -0
  111. data/resources/locales/fil/lists.yml +7 -0
  112. data/resources/locales/fil/numbers.yml +27 -27
  113. data/resources/locales/fil/plurals.yml +2 -3
  114. data/resources/locales/fil/units.yml +80 -80
  115. data/resources/locales/fr/calendars.yml +83 -83
  116. data/resources/locales/fr/languages.yml +117 -117
  117. data/resources/locales/fr/layout.yml +5 -0
  118. data/resources/locales/fr/lists.yml +7 -0
  119. data/resources/locales/fr/numbers.yml +37 -37
  120. data/resources/locales/fr/plurals.yml +2 -3
  121. data/resources/locales/fr/units.yml +80 -80
  122. data/resources/locales/he/calendars.yml +155 -154
  123. data/resources/locales/he/languages.yml +282 -282
  124. data/resources/locales/he/layout.yml +5 -0
  125. data/resources/locales/he/lists.yml +7 -0
  126. data/resources/locales/he/numbers.yml +27 -27
  127. data/resources/locales/he/plurals.yml +2 -3
  128. data/resources/locales/he/units.yml +122 -122
  129. data/resources/locales/hi/calendars.yml +132 -131
  130. data/resources/locales/hi/languages.yml +511 -511
  131. data/resources/locales/hi/layout.yml +5 -0
  132. data/resources/locales/hi/lists.yml +7 -0
  133. data/resources/locales/hi/numbers.yml +27 -27
  134. data/resources/locales/hi/plurals.yml +2 -3
  135. data/resources/locales/hi/units.yml +122 -122
  136. data/resources/locales/hu/calendars.yml +121 -120
  137. data/resources/locales/hu/languages.yml +214 -214
  138. data/resources/locales/hu/layout.yml +5 -0
  139. data/resources/locales/hu/lists.yml +7 -0
  140. data/resources/locales/hu/numbers.yml +39 -39
  141. data/resources/locales/hu/plurals.yml +2 -3
  142. data/resources/locales/hu/units.yml +102 -102
  143. data/resources/locales/id/calendars.yml +68 -67
  144. data/resources/locales/id/languages.yml +21 -21
  145. data/resources/locales/id/layout.yml +5 -0
  146. data/resources/locales/id/lists.yml +7 -0
  147. data/resources/locales/id/numbers.yml +37 -37
  148. data/resources/locales/id/plurals.yml +2 -3
  149. data/resources/locales/id/units.yml +73 -73
  150. data/resources/locales/it/calendars.yml +81 -80
  151. data/resources/locales/it/languages.yml +20 -20
  152. data/resources/locales/it/layout.yml +5 -0
  153. data/resources/locales/it/lists.yml +7 -0
  154. data/resources/locales/it/numbers.yml +36 -36
  155. data/resources/locales/it/plurals.yml +2 -3
  156. data/resources/locales/it/units.yml +94 -94
  157. data/resources/locales/ja/calendars.yml +123 -122
  158. data/resources/locales/ja/languages.yml +516 -516
  159. data/resources/locales/ja/layout.yml +5 -0
  160. data/resources/locales/ja/lists.yml +7 -0
  161. data/resources/locales/ja/numbers.yml +38 -38
  162. data/resources/locales/ja/plurals.yml +2 -3
  163. data/resources/locales/ja/units.yml +108 -108
  164. data/resources/locales/ko/calendars.yml +141 -140
  165. data/resources/locales/ko/languages.yml +509 -509
  166. data/resources/locales/ko/layout.yml +5 -0
  167. data/resources/locales/ko/lists.yml +7 -0
  168. data/resources/locales/ko/numbers.yml +37 -37
  169. data/resources/locales/ko/plurals.yml +2 -3
  170. data/resources/locales/ko/units.yml +108 -108
  171. data/resources/locales/ms/calendars.yml +68 -67
  172. data/resources/locales/ms/languages.yml +19 -19
  173. data/resources/locales/ms/layout.yml +5 -0
  174. data/resources/locales/ms/lists.yml +7 -0
  175. data/resources/locales/ms/numbers.yml +26 -26
  176. data/resources/locales/ms/plurals.yml +2 -3
  177. data/resources/locales/ms/units.yml +73 -73
  178. data/resources/locales/nb/calendars.yml +78 -78
  179. data/resources/locales/nb/languages.yml +93 -93
  180. data/resources/locales/nb/layout.yml +5 -0
  181. data/resources/locales/nb/lists.yml +7 -0
  182. data/resources/locales/nb/numbers.yml +37 -37
  183. data/resources/locales/nb/plurals.yml +2 -3
  184. data/resources/locales/nb/units.yml +99 -99
  185. data/resources/locales/nl/calendars.yml +67 -67
  186. data/resources/locales/nl/languages.yml +30 -30
  187. data/resources/locales/nl/layout.yml +5 -0
  188. data/resources/locales/nl/lists.yml +7 -0
  189. data/resources/locales/nl/numbers.yml +36 -36
  190. data/resources/locales/nl/plurals.yml +2 -3
  191. data/resources/locales/nl/units.yml +87 -87
  192. data/resources/locales/pl/calendars.yml +102 -101
  193. data/resources/locales/pl/languages.yml +139 -139
  194. data/resources/locales/pl/layout.yml +5 -0
  195. data/resources/locales/pl/lists.yml +7 -0
  196. data/resources/locales/pl/numbers.yml +41 -41
  197. data/resources/locales/pl/plurals.yml +2 -5
  198. data/resources/locales/pl/units.yml +149 -149
  199. data/resources/locales/pt/calendars.yml +83 -83
  200. data/resources/locales/pt/languages.yml +161 -161
  201. data/resources/locales/pt/layout.yml +5 -0
  202. data/resources/locales/pt/lists.yml +7 -0
  203. data/resources/locales/pt/numbers.yml +39 -39
  204. data/resources/locales/pt/plurals.yml +2 -3
  205. data/resources/locales/pt/units.yml +110 -110
  206. data/resources/locales/ru/calendars.yml +213 -212
  207. data/resources/locales/ru/languages.yml +511 -511
  208. data/resources/locales/ru/layout.yml +5 -0
  209. data/resources/locales/ru/lists.yml +7 -0
  210. data/resources/locales/ru/numbers.yml +40 -40
  211. data/resources/locales/ru/plurals.yml +2 -5
  212. data/resources/locales/ru/units.yml +192 -192
  213. data/resources/locales/sv/calendars.yml +85 -85
  214. data/resources/locales/sv/languages.yml +108 -108
  215. data/resources/locales/sv/layout.yml +5 -0
  216. data/resources/locales/sv/lists.yml +7 -0
  217. data/resources/locales/sv/numbers.yml +39 -39
  218. data/resources/locales/sv/plurals.yml +2 -3
  219. data/resources/locales/sv/units.yml +116 -116
  220. data/resources/locales/th/calendars.yml +172 -171
  221. data/resources/locales/th/languages.yml +510 -510
  222. data/resources/locales/th/layout.yml +5 -0
  223. data/resources/locales/th/lists.yml +7 -0
  224. data/resources/locales/th/numbers.yml +38 -38
  225. data/resources/locales/th/plurals.yml +2 -3
  226. data/resources/locales/th/units.yml +107 -107
  227. data/resources/locales/tr/calendars.yml +117 -116
  228. data/resources/locales/tr/languages.yml +143 -143
  229. data/resources/locales/tr/layout.yml +5 -0
  230. data/resources/locales/tr/lists.yml +7 -0
  231. data/resources/locales/tr/numbers.yml +37 -37
  232. data/resources/locales/tr/plurals.yml +2 -3
  233. data/resources/locales/tr/units.yml +98 -98
  234. data/resources/locales/uk/calendars.yml +187 -186
  235. data/resources/locales/uk/languages.yml +520 -520
  236. data/resources/locales/uk/layout.yml +5 -0
  237. data/resources/locales/uk/lists.yml +7 -0
  238. data/resources/locales/uk/numbers.yml +44 -44
  239. data/resources/locales/uk/plurals.yml +2 -5
  240. data/resources/locales/uk/units.yml +192 -192
  241. data/resources/locales/ur/calendars.yml +112 -111
  242. data/resources/locales/ur/languages.yml +164 -164
  243. data/resources/locales/ur/layout.yml +5 -0
  244. data/resources/locales/ur/lists.yml +7 -0
  245. data/resources/locales/ur/numbers.yml +27 -27
  246. data/resources/locales/ur/plurals.yml +2 -3
  247. data/resources/locales/ur/units.yml +136 -136
  248. data/resources/locales/zh/calendars.yml +212 -211
  249. data/resources/locales/zh/languages.yml +506 -506
  250. data/resources/locales/zh/layout.yml +5 -0
  251. data/resources/locales/zh/lists.yml +7 -0
  252. data/resources/locales/zh/numbers.yml +37 -37
  253. data/resources/locales/zh/plurals.yml +2 -3
  254. data/resources/locales/zh/units.yml +108 -108
  255. data/resources/locales/zh-Hant/calendars.yml +159 -158
  256. data/resources/locales/zh-Hant/languages.yml +510 -510
  257. data/resources/locales/zh-Hant/layout.yml +5 -0
  258. data/resources/locales/zh-Hant/lists.yml +7 -0
  259. data/resources/locales/zh-Hant/numbers.yml +38 -38
  260. data/resources/locales/zh-Hant/plurals.yml +2 -3
  261. data/resources/locales/zh-Hant/units.yml +108 -108
  262. data/spec/bidi/bidi_spec.rb +72 -0
  263. data/spec/bidi/classpath_bidi_test.txt +217202 -0
  264. data/spec/collation/tailoring_tests/da.txt +1 -1
  265. data/spec/collation/tailoring_tests/fi.txt +1 -7
  266. data/spec/collation/tailoring_tests/zh-Hant.txt +1 -1
  267. data/spec/formatters/list_formatter_spec.rb +119 -0
  268. data/spec/localized/localized_array_spec.rb +28 -0
  269. data/spec/localized/localized_hash_spec.rb +22 -0
  270. data/spec/localized/localized_number_spec.rb +3 -3
  271. data/spec/localized/localized_string_spec.rb +52 -1
  272. data/spec/localized/localized_symbol_spec.rb +7 -0
  273. data/spec/normalization/base_spec.rb +2 -4
  274. data/spec/shared/languages_spec.rb +21 -0
  275. data/spec/shared/numbers_spec.rb +4 -4
  276. data/spec/spec_helper.rb +3 -1
  277. data/spec/utils/yaml/t.gif +0 -0
  278. data/spec/utils/yaml/t.yaml +5 -0
  279. data/spec/utils/yaml/yaml_spec.rb +426 -0
  280. metadata +82 -2
@@ -0,0 +1,526 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ # This code was adapted from GNU Classpath, but modified significantly. Ordinarily, derivatives are
7
+ # treated as falling under the same license as the original source, but classpath comes with the
8
+ # following exception:
9
+ #
10
+ # "As a special exception, the copyright holders of this library give you
11
+ # permission to link this library with independent modules to produce an
12
+ # executable, regardless of the license terms of these independent
13
+ # modules, and to copy and distribute the resulting executable under
14
+ # terms of your choice, provided that you also meet, for each linked
15
+ # independent module, the terms and conditions of the license of that
16
+ # module. An independent module is a module which is not derived from
17
+ # or based on this library. If you modify this library, you may extend
18
+ # this exception to your version of the library, but you are not
19
+ # obligated to do so. If you do not wish to do so, delete this
20
+ # exception statement from your version."
21
+ #
22
+ # We are assuming here that building a gem with the compiled version of bidi.java falls under these terms,
23
+ # specifically that we are "link(ing) this library with independent modules to produce an executable."
24
+ # We are NOT including the original source code to avoid licensing restrictions, but it can be viewed here:
25
+ # http://developer.classpath.org/doc/java/text/Bidi-source.html
26
+
27
+
28
+ module TwitterCldr
29
+ module Shared
30
+ class Bidi
31
+ attr_reader :types, :levels, :string_arr
32
+
33
+ MAX_DEPTH = 62
34
+
35
+ class << self
36
+ def from_string(str, options = {})
37
+ string_arr = str.unpack("U*")
38
+ Bidi.new(options.merge(:types => compute_types(string_arr), :string_arr => string_arr))
39
+ end
40
+
41
+ def from_type_array(types, options = {})
42
+ Bidi.new(options.merge(:types => types))
43
+ end
44
+
45
+ protected
46
+
47
+ def compute_types(arr)
48
+ arr.map do |code_point|
49
+ TwitterCldr::Shared::CodePoint.find(code_point).bidi_class.to_sym
50
+ end
51
+ end
52
+ end
53
+
54
+ def initialize(options = {})
55
+ @string_arr = options[:string_arr] || options[:types]
56
+ @types = options[:types] || []
57
+ @levels = []
58
+ @runs = []
59
+ @direction = options[:direction]
60
+ @default_direction = options[:default_direction] || :LTR
61
+ @length = @types.size
62
+ run_bidi
63
+ end
64
+
65
+ def to_s
66
+ @string_arr.pack("U*")
67
+ end
68
+
69
+ def reorder_visually!
70
+ raise "No string given!" unless @string_arr
71
+
72
+ # Do this explicitly so we can also find the maximum depth at the
73
+ # same time.
74
+ max = 0
75
+ lowest_odd = MAX_DEPTH + 1
76
+
77
+ @levels.each do |level|
78
+ max = [level, max].max
79
+ lowest_odd = [lowest_odd, level].min unless level.even?
80
+ end
81
+
82
+ # Reverse the runs starting with the deepest.
83
+ max.downto(lowest_odd) do |depth|
84
+ start = 0
85
+
86
+ while start < @levels.size
87
+ # Find the start of a run >= DEPTH.
88
+ start += 1 while start < @levels.size && @levels[start] < depth
89
+
90
+ break if start == @levels.size
91
+
92
+ # Find the end of the run.
93
+ finish = start + 1
94
+ finish += 1 while finish < @levels.size && @levels[finish] >= depth
95
+
96
+ # Reverse this run.
97
+ ((finish - start) / 2).times do |i|
98
+ tmpb = @levels[finish - i - 1]
99
+ @levels[finish - i - 1] = @levels[start + i]
100
+ @levels[start + i] = tmpb
101
+
102
+ tmpo = @string_arr[finish - i - 1]
103
+ @string_arr[finish - i - 1] = @string_arr[start + i]
104
+ @string_arr[start + i] = tmpo
105
+ end
106
+
107
+ # Handle the next run.
108
+ start = finish + 1
109
+ end
110
+ end
111
+
112
+ self
113
+ end
114
+
115
+ protected
116
+
117
+ def compute_paragraph_embedding_level
118
+ # First check to see if the user supplied a directionality override.
119
+ if [:LTR, :RTL].include?(@direction)
120
+ @direction == :LTR ? 0 : 1
121
+ else
122
+ # This implements rules P2 and P3.
123
+ # (Note that we don't need P1, as the user supplies
124
+ # a paragraph.)
125
+ @types.each do |type|
126
+ return 0 if type == :L
127
+ return 1 if type == :R
128
+ end
129
+
130
+ @default_direction == :LTR ? 0 : 1
131
+ end
132
+ end
133
+
134
+ def compute_explicit_levels
135
+ current_embedding = @base_embedding
136
+
137
+ # The directional override is a Character directionality
138
+ # constant. -1 means there is no override.
139
+ directional_override = -1
140
+
141
+ # The stack of pushed embeddings, and the stack pointer.
142
+ # Note that because the direction is inherent in the depth,
143
+ # and because we have a bit left over in a byte, we can encode
144
+ # the override, if any, directly in this value on the stack.
145
+
146
+ embedding_stack = []
147
+ @formatter_indices ||= []
148
+ sp = 0
149
+
150
+ @length.times do |i|
151
+ is_ltr = false
152
+ is_special = true
153
+ is_ltr = @types[i] == :LRE || @types[i] == :LRO
154
+
155
+ case @types[i]
156
+ when :RLE, :RLO, :LRE, :LRO
157
+ new_embedding = if is_ltr
158
+ # Least greater even.
159
+ ((current_embedding & ~1) + 2)
160
+ else
161
+ # Least greater odd.
162
+ ((current_embedding + 1) | 1)
163
+ end
164
+
165
+ # FIXME: we don't properly handle invalid pushes.
166
+ if new_embedding < MAX_DEPTH
167
+ # The new level is valid. Push the old value.
168
+ # See above for a comment on the encoding here.
169
+
170
+ current_embedding |= -0x80 if (directional_override != -1)
171
+ embedding_stack[sp] = current_embedding
172
+ current_embedding = new_embedding
173
+ sp += 1
174
+
175
+ directional_override = if @types[i] == :LRO
176
+ :L
177
+ elsif @types[i] == :RLO
178
+ :R
179
+ else
180
+ -1
181
+ end
182
+ end
183
+
184
+ when :PDF
185
+ # FIXME: we don't properly handle a pop with a corresponding
186
+ # invalid push.
187
+ # If sp === 0, we saw a pop without a push. Just ignore it.
188
+ if sp > 0
189
+ sp -= 1
190
+ new_embedding = embedding_stack[sp]
191
+ current_embedding = new_embedding & 0x7f
192
+
193
+ directional_override = if new_embedding < 0
194
+ (new_embedding & 1) == 0 ? :L : :R
195
+ else
196
+ -1
197
+ end
198
+ end
199
+
200
+ else
201
+ is_special = false
202
+ end
203
+
204
+ @levels[i] = current_embedding
205
+
206
+ if is_special
207
+ # Mark this character for removal.
208
+ @formatter_indices << i
209
+ elsif directional_override != -1
210
+ @types[i] = directional_override
211
+ end
212
+ end
213
+
214
+ # Remove the formatting codes and update both the arrays
215
+ # and 'length'. It would be more efficient not to remove
216
+ # these codes, but it is also more complicated. Also, the
217
+ # Unicode algorithm reference does not properly describe
218
+ # how this is to be done -- from what I can tell, their suggestions
219
+ # in this area will not yield the correct results.
220
+
221
+ output = 0
222
+ input = 0
223
+ size = @formatter_indices.size
224
+
225
+ 0.upto(size).each do |i|
226
+ if i == size
227
+ next_fmt = @length
228
+ else
229
+ next_fmt = @formatter_indices[i]
230
+ end
231
+
232
+ len = next_fmt - input
233
+
234
+ # Non-formatter codes are from 'input' to 'next_fmt'.
235
+ arraycopy(@levels, input, @levels, output, len)
236
+ arraycopy(@types, input, @types, output, len)
237
+
238
+ output += len
239
+ input = next_fmt + 1
240
+ end
241
+
242
+ @length -= @formatter_indices.size
243
+ end
244
+
245
+ def compute_runs
246
+ run_count = 0
247
+ current_embedding = @base_embedding
248
+
249
+ @length.times do |i|
250
+ if @levels[i] != current_embedding
251
+ current_embedding = @levels[i]
252
+ run_count += 1
253
+ end
254
+ end
255
+
256
+ # This may be called multiple times. If so, and if
257
+ # the number of runs has not changed, then don't bother
258
+ # allocating a new array.
259
+ where = 0
260
+ last_run_start = 0
261
+ current_embedding = @base_embedding
262
+
263
+ @length.times do |i|
264
+ if @levels[i] != current_embedding
265
+ @runs[where] = last_run_start
266
+ where += 1
267
+ last_run_start = i
268
+ current_embedding = @levels[i]
269
+ end
270
+ end
271
+
272
+ @runs[where] = last_run_start
273
+ end
274
+
275
+ def resolve_weak_types
276
+ run_count = @runs.size
277
+ previous_level = @base_embedding
278
+
279
+ run_count.times do |run_idx|
280
+ start = get_run_start(run_idx)
281
+ finish = get_run_limit(run_idx)
282
+ level = get_run_level(run_idx) || 0
283
+
284
+ # These are the names used in the Bidi algorithm.
285
+ sor = [previous_level, level].max.even? ? :L : :R
286
+
287
+ next_level = if run_idx == (run_count - 1)
288
+ @base_embedding
289
+ else
290
+ get_run_level(run_idx + 1) || 0
291
+ end
292
+
293
+ eor = [level, next_level].max.even? ? :L : :R
294
+ prev_type = sor
295
+ prev_strong_type = sor
296
+
297
+ start.upto(finish - 1) do |i|
298
+ next_type = (i == finish - 1) ? eor : @types[i + 1]
299
+
300
+ # Rule W1: change NSM to the prevailing direction.
301
+ if @types[i] == :NSM
302
+ @types[i] = prev_type
303
+ else
304
+ prev_type = @types[i]
305
+ end
306
+
307
+ # Rule W2: change EN to AN in some cases.
308
+ if @types[i] == :EN
309
+ if prev_strong_type == :AL
310
+ @types[i] = :AN
311
+ end
312
+ elsif @types[i] == :L || @types[i] == :R || @types[i] == :AL
313
+ prev_strong_type = @types[i]
314
+ end
315
+
316
+ # Rule W3: change AL to R.
317
+ if @types[i] == :AL
318
+ @types[i] = :R
319
+ end
320
+
321
+ # Rule W4: handle separators between two numbers.
322
+ if prev_type == :EN && next_type == :EN
323
+ if @types[i] == :ES || @types[i] == :CS
324
+ @types[i] = nextType
325
+ end
326
+ elsif prev_type == :AN && next_type == :AN && @types[i] == :CS
327
+ @types[i] = next_type
328
+ end
329
+
330
+ # Rule W5: change a sequence of european terminators to
331
+ # european numbers, if they are adjacent to european numbers.
332
+ # We also include BN characters in this.
333
+ if @types[i] == :ET || @types[i] == :BN
334
+ if prev_type == :EN
335
+ @types[i] = prev_type
336
+ else
337
+ # Look ahead to see if there is an EN terminating this
338
+ # sequence of ETs.
339
+ j = i + 1
340
+
341
+ while j < finish && @types[j] == :ET || @types[j] == :BN
342
+ j += 1
343
+ end
344
+
345
+ if j < finish && @types[j] == :EN
346
+ # Change them all to EN now.
347
+ i.upto(j - 1) do |k|
348
+ @types[k] = :EN
349
+ end
350
+ end
351
+ end
352
+ end
353
+
354
+ # Rule W6: separators and terminators change to ON.
355
+ # Again we include BN.
356
+ if @types[i] == :ET || @types[i] == :CS || @types[i] == :BN
357
+ @types[i] = :ON
358
+ end
359
+
360
+ # Rule W7: change european number types.
361
+ if prev_strong_type == :L && @types[i] == :EN
362
+ @types[i] = prev_strong_type
363
+ end
364
+ end
365
+
366
+ previous_level = level
367
+ end
368
+ end
369
+
370
+ def get_run_count
371
+ @runs.size
372
+ end
373
+
374
+ def get_run_level(which)
375
+ @levels[@runs[which]]
376
+ end
377
+
378
+ def get_run_limit(which)
379
+ if which == (@runs.length - 1)
380
+ @length
381
+ else
382
+ @runs[which + 1]
383
+ end
384
+ end
385
+
386
+ def get_run_start(which)
387
+ @runs[which]
388
+ end
389
+
390
+ def resolve_implicit_levels
391
+ # This implements rules I1 and I2.
392
+ @length.times do |i|
393
+ if (@levels[i] & 1) == 0
394
+ if @types[i] == :R
395
+ @levels[i] += 1
396
+ elsif @types[i] == :AN || @types[i] == :EN
397
+ @levels[i] += 2
398
+ end
399
+ else
400
+ if @types[i] == :L || @types[i] == :AN || @types[i] == :EN
401
+ @levels[i] += 1
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ def resolve_neutral_types
408
+ # This implements rules N1 and N2.
409
+ run_count = get_run_count
410
+ previous_level = @base_embedding
411
+
412
+ run_count.times do |run|
413
+ start = get_run_start(run)
414
+ finish = get_run_limit(run)
415
+ level = get_run_level(run)
416
+ next unless level
417
+
418
+ embedding_direction = level.even? ? :L : :R
419
+ # These are the names used in the Bidi algorithm.
420
+ sor = [previous_level, level].max.even? ? :L : :R
421
+
422
+ next_level = if run == (run_count - 1)
423
+ @base_embedding
424
+ else
425
+ get_run_level(run + 1)
426
+ end
427
+
428
+ eor = [level, next_level].max.even? ? :L : :R
429
+ prev_strong = sor
430
+ neutral_start = -1
431
+
432
+ start.upto(finish) do |i|
433
+ new_strong = -1
434
+ this_type = i == finish ? eor : @types[i]
435
+
436
+ case this_type
437
+ when :L
438
+ new_strong = :L
439
+ when :R, :AN, :EN
440
+ new_strong = :R
441
+ when :BN, :ON, :S, :B, :WS
442
+ neutral_start = i if neutral_start == -1
443
+ end
444
+
445
+ # If we see a strong character, update all the neutrals.
446
+ if new_strong != -1
447
+ if neutral_start != -1
448
+ override = prev_strong == new_strong ? prev_strong : embedding_direction
449
+ neutral_start.upto(i - 1) { |j| @types[j] = override }
450
+ end
451
+
452
+ prev_strong = new_strong
453
+ neutral_start = -1
454
+ end
455
+ end
456
+
457
+ previous_level = level
458
+ end
459
+ end
460
+
461
+ def reinsert_formatting_codes
462
+ if @formatter_indices
463
+ input = @length
464
+ output = @levels.size
465
+
466
+ # Process from the end as we are copying the array over itself here.
467
+ (@formatter_indices.size - 1).downto(0) do |index|
468
+ next_fmt = @formatter_indices[index]
469
+
470
+ # nextFmt points to a location in the original array. So,
471
+ # nextFmt+1 is the target of our copying. output is the location
472
+ # to which we last copied, thus we can derive the length of the
473
+ # copy from it.
474
+ len = output - next_fmt - 1
475
+ output = next_fmt
476
+ input -= len
477
+
478
+ # Note that we no longer need 'types' at this point, so we
479
+ # only edit 'levels'.
480
+ if next_fmt + 1 < @levels.size
481
+ arraycopy(@levels, input, @levels, next_fmt + 1, len)
482
+ end
483
+
484
+ # Now set the level at the reinsertion point.
485
+ right_level = if output == @levels.length - 1
486
+ @base_embedding
487
+ else
488
+ @levels[output + 1] || 0
489
+ end
490
+
491
+ left_level = if input == 0
492
+ @base_embedding
493
+ else
494
+ @levels[input] || 0;
495
+ end
496
+
497
+ @levels[output] = [left_level, right_level].max
498
+ end
499
+ end
500
+
501
+ @length = @levels.size
502
+ end
503
+
504
+ def arraycopy(orig, orig_index, dest, dest_index, length)
505
+ orig[orig_index...(orig_index + length)].each_with_index do |elem, count|
506
+ dest[dest_index + count] = elem
507
+ end
508
+ end
509
+
510
+ def run_bidi
511
+ @base_embedding = compute_paragraph_embedding_level
512
+
513
+ compute_explicit_levels
514
+ compute_runs
515
+ resolve_weak_types
516
+ resolve_neutral_types
517
+ resolve_implicit_levels
518
+ reinsert_formatting_codes
519
+
520
+ # After resolving the implicit levels, the number
521
+ # of runs may have changed.
522
+ compute_runs
523
+ end
524
+ end
525
+ end
526
+ end
@@ -36,6 +36,11 @@ module TwitterCldr
36
36
  nil
37
37
  end
38
38
 
39
+ def is_rtl?(locale)
40
+ locale = TwitterCldr.convert_locale(locale)
41
+ TwitterCldr.get_locale_resource(locale, :layout)[locale][:layout][:orientation][:characters] == "right-to-left"
42
+ end
43
+
39
44
  protected
40
45
 
41
46
  def get_resource(locale)
@@ -13,5 +13,6 @@ module TwitterCldr
13
13
  autoload :Numbers, 'twitter_cldr/shared/numbers'
14
14
  autoload :PhoneCodes, 'twitter_cldr/shared/phone_codes'
15
15
  autoload :PostalCodes, 'twitter_cldr/shared/postal_codes'
16
+ autoload :Bidi, 'twitter_cldr/shared/bidi'
16
17
  end
17
18
  end
@@ -30,7 +30,7 @@ module TwitterCldr
30
30
  end
31
31
 
32
32
  def to_string(code_points)
33
- code_points.map{ |code_point| to_char(code_point) }.join
33
+ code_points.map { |code_point| to_char(code_point) }.join
34
34
  end
35
35
 
36
36
  end