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.
- data/Gemfile +3 -2
- data/History.txt +7 -1
- data/README.md +55 -0
- data/lib/twitter_cldr/core_ext.rb +1 -1
- data/lib/twitter_cldr/formatters/list_formatter.rb +64 -0
- data/lib/twitter_cldr/formatters.rb +4 -2
- data/lib/twitter_cldr/localized/localized_array.rb +19 -1
- data/lib/twitter_cldr/localized/localized_hash.rb +20 -0
- data/lib/twitter_cldr/localized/localized_string.rb +46 -1
- data/lib/twitter_cldr/localized/localized_symbol.rb +4 -0
- data/lib/twitter_cldr/localized.rb +1 -0
- data/lib/twitter_cldr/resources/bidi_test_importer.rb +118 -0
- data/lib/twitter_cldr/resources/locales_resources_importer.rb +1 -1
- data/lib/twitter_cldr/resources.rb +1 -0
- data/lib/twitter_cldr/shared/bidi.rb +526 -0
- data/lib/twitter_cldr/shared/languages.rb +5 -0
- data/lib/twitter_cldr/shared.rb +1 -0
- data/lib/twitter_cldr/utils/code_points.rb +1 -1
- data/lib/twitter_cldr/utils/yaml.rb +390 -0
- data/lib/twitter_cldr/utils.rb +1 -0
- data/lib/twitter_cldr/version.rb +1 -1
- data/lib/twitter_cldr.rb +2 -0
- data/resources/custom/locales/en/units.yml +19 -18
- data/resources/locales/af/calendars.yml +67 -66
- data/resources/locales/af/languages.yml +22 -22
- data/resources/locales/af/layout.yml +5 -0
- data/resources/locales/af/lists.yml +7 -0
- data/resources/locales/af/numbers.yml +36 -36
- data/resources/locales/af/plurals.yml +2 -3
- data/resources/locales/af/units.yml +75 -75
- data/resources/locales/ar/calendars.yml +149 -148
- data/resources/locales/ar/languages.yml +501 -501
- data/resources/locales/ar/layout.yml +5 -0
- data/resources/locales/ar/lists.yml +7 -0
- data/resources/locales/ar/numbers.yml +31 -31
- data/resources/locales/ar/plurals.yml +2 -9
- data/resources/locales/ar/units.yml +220 -220
- data/resources/locales/ca/calendars.yml +78 -77
- data/resources/locales/ca/languages.yml +199 -199
- data/resources/locales/ca/layout.yml +5 -0
- data/resources/locales/ca/lists.yml +7 -0
- data/resources/locales/ca/numbers.yml +36 -36
- data/resources/locales/ca/plurals.yml +2 -3
- data/resources/locales/ca/units.yml +108 -108
- data/resources/locales/cs/calendars.yml +141 -140
- data/resources/locales/cs/languages.yml +399 -399
- data/resources/locales/cs/layout.yml +5 -0
- data/resources/locales/cs/lists.yml +7 -0
- data/resources/locales/cs/numbers.yml +41 -41
- data/resources/locales/cs/plurals.yml +2 -3
- data/resources/locales/cs/units.yml +142 -142
- data/resources/locales/da/calendars.yml +73 -73
- data/resources/locales/da/languages.yml +36 -36
- data/resources/locales/da/layout.yml +5 -0
- data/resources/locales/da/lists.yml +7 -0
- data/resources/locales/da/numbers.yml +37 -37
- data/resources/locales/da/plurals.yml +2 -3
- data/resources/locales/da/units.yml +97 -97
- data/resources/locales/de/calendars.yml +71 -71
- data/resources/locales/de/languages.yml +51 -51
- data/resources/locales/de/layout.yml +5 -0
- data/resources/locales/de/lists.yml +7 -0
- data/resources/locales/de/numbers.yml +36 -36
- data/resources/locales/de/plurals.yml +2 -3
- data/resources/locales/de/units.yml +108 -108
- data/resources/locales/el/calendars.yml +213 -212
- data/resources/locales/el/languages.yml +520 -520
- data/resources/locales/el/layout.yml +5 -0
- data/resources/locales/el/lists.yml +7 -0
- data/resources/locales/el/numbers.yml +39 -39
- data/resources/locales/el/plurals.yml +2 -3
- data/resources/locales/el/units.yml +143 -143
- data/resources/locales/en/calendars.yml +66 -65
- data/resources/locales/en/languages.yml +24 -24
- data/resources/locales/en/layout.yml +5 -0
- data/resources/locales/en/lists.yml +7 -0
- data/resources/locales/en/numbers.yml +27 -27
- data/resources/locales/en/plurals.yml +2 -3
- data/resources/locales/en/units.yml +94 -94
- data/resources/locales/es/calendars.yml +80 -79
- data/resources/locales/es/languages.yml +139 -139
- data/resources/locales/es/layout.yml +5 -0
- data/resources/locales/es/lists.yml +7 -0
- data/resources/locales/es/numbers.yml +36 -36
- data/resources/locales/es/plurals.yml +2 -3
- data/resources/locales/es/units.yml +96 -96
- data/resources/locales/eu/calendars.yml +68 -67
- data/resources/locales/eu/languages.yml +11 -11
- data/resources/locales/eu/layout.yml +5 -0
- data/resources/locales/eu/lists.yml +7 -0
- data/resources/locales/eu/numbers.yml +36 -36
- data/resources/locales/eu/plurals.yml +2 -3
- data/resources/locales/eu/units.yml +80 -80
- data/resources/locales/fa/calendars.yml +223 -222
- data/resources/locales/fa/languages.yml +489 -489
- data/resources/locales/fa/layout.yml +5 -0
- data/resources/locales/fa/lists.yml +7 -0
- data/resources/locales/fa/numbers.yml +26 -26
- data/resources/locales/fa/plurals.yml +2 -3
- data/resources/locales/fa/units.yml +122 -122
- data/resources/locales/fi/calendars.yml +87 -87
- data/resources/locales/fi/languages.yml +86 -86
- data/resources/locales/fi/layout.yml +5 -0
- data/resources/locales/fi/lists.yml +7 -0
- data/resources/locales/fi/numbers.yml +41 -41
- data/resources/locales/fi/plurals.yml +2 -3
- data/resources/locales/fi/units.yml +124 -124
- data/resources/locales/fil/calendars.yml +68 -67
- data/resources/locales/fil/languages.yml +19 -19
- data/resources/locales/fil/layout.yml +5 -0
- data/resources/locales/fil/lists.yml +7 -0
- data/resources/locales/fil/numbers.yml +27 -27
- data/resources/locales/fil/plurals.yml +2 -3
- data/resources/locales/fil/units.yml +80 -80
- data/resources/locales/fr/calendars.yml +83 -83
- data/resources/locales/fr/languages.yml +117 -117
- data/resources/locales/fr/layout.yml +5 -0
- data/resources/locales/fr/lists.yml +7 -0
- data/resources/locales/fr/numbers.yml +37 -37
- data/resources/locales/fr/plurals.yml +2 -3
- data/resources/locales/fr/units.yml +80 -80
- data/resources/locales/he/calendars.yml +155 -154
- data/resources/locales/he/languages.yml +282 -282
- data/resources/locales/he/layout.yml +5 -0
- data/resources/locales/he/lists.yml +7 -0
- data/resources/locales/he/numbers.yml +27 -27
- data/resources/locales/he/plurals.yml +2 -3
- data/resources/locales/he/units.yml +122 -122
- data/resources/locales/hi/calendars.yml +132 -131
- data/resources/locales/hi/languages.yml +511 -511
- data/resources/locales/hi/layout.yml +5 -0
- data/resources/locales/hi/lists.yml +7 -0
- data/resources/locales/hi/numbers.yml +27 -27
- data/resources/locales/hi/plurals.yml +2 -3
- data/resources/locales/hi/units.yml +122 -122
- data/resources/locales/hu/calendars.yml +121 -120
- data/resources/locales/hu/languages.yml +214 -214
- data/resources/locales/hu/layout.yml +5 -0
- data/resources/locales/hu/lists.yml +7 -0
- data/resources/locales/hu/numbers.yml +39 -39
- data/resources/locales/hu/plurals.yml +2 -3
- data/resources/locales/hu/units.yml +102 -102
- data/resources/locales/id/calendars.yml +68 -67
- data/resources/locales/id/languages.yml +21 -21
- data/resources/locales/id/layout.yml +5 -0
- data/resources/locales/id/lists.yml +7 -0
- data/resources/locales/id/numbers.yml +37 -37
- data/resources/locales/id/plurals.yml +2 -3
- data/resources/locales/id/units.yml +73 -73
- data/resources/locales/it/calendars.yml +81 -80
- data/resources/locales/it/languages.yml +20 -20
- data/resources/locales/it/layout.yml +5 -0
- data/resources/locales/it/lists.yml +7 -0
- data/resources/locales/it/numbers.yml +36 -36
- data/resources/locales/it/plurals.yml +2 -3
- data/resources/locales/it/units.yml +94 -94
- data/resources/locales/ja/calendars.yml +123 -122
- data/resources/locales/ja/languages.yml +516 -516
- data/resources/locales/ja/layout.yml +5 -0
- data/resources/locales/ja/lists.yml +7 -0
- data/resources/locales/ja/numbers.yml +38 -38
- data/resources/locales/ja/plurals.yml +2 -3
- data/resources/locales/ja/units.yml +108 -108
- data/resources/locales/ko/calendars.yml +141 -140
- data/resources/locales/ko/languages.yml +509 -509
- data/resources/locales/ko/layout.yml +5 -0
- data/resources/locales/ko/lists.yml +7 -0
- data/resources/locales/ko/numbers.yml +37 -37
- data/resources/locales/ko/plurals.yml +2 -3
- data/resources/locales/ko/units.yml +108 -108
- data/resources/locales/ms/calendars.yml +68 -67
- data/resources/locales/ms/languages.yml +19 -19
- data/resources/locales/ms/layout.yml +5 -0
- data/resources/locales/ms/lists.yml +7 -0
- data/resources/locales/ms/numbers.yml +26 -26
- data/resources/locales/ms/plurals.yml +2 -3
- data/resources/locales/ms/units.yml +73 -73
- data/resources/locales/nb/calendars.yml +78 -78
- data/resources/locales/nb/languages.yml +93 -93
- data/resources/locales/nb/layout.yml +5 -0
- data/resources/locales/nb/lists.yml +7 -0
- data/resources/locales/nb/numbers.yml +37 -37
- data/resources/locales/nb/plurals.yml +2 -3
- data/resources/locales/nb/units.yml +99 -99
- data/resources/locales/nl/calendars.yml +67 -67
- data/resources/locales/nl/languages.yml +30 -30
- data/resources/locales/nl/layout.yml +5 -0
- data/resources/locales/nl/lists.yml +7 -0
- data/resources/locales/nl/numbers.yml +36 -36
- data/resources/locales/nl/plurals.yml +2 -3
- data/resources/locales/nl/units.yml +87 -87
- data/resources/locales/pl/calendars.yml +102 -101
- data/resources/locales/pl/languages.yml +139 -139
- data/resources/locales/pl/layout.yml +5 -0
- data/resources/locales/pl/lists.yml +7 -0
- data/resources/locales/pl/numbers.yml +41 -41
- data/resources/locales/pl/plurals.yml +2 -5
- data/resources/locales/pl/units.yml +149 -149
- data/resources/locales/pt/calendars.yml +83 -83
- data/resources/locales/pt/languages.yml +161 -161
- data/resources/locales/pt/layout.yml +5 -0
- data/resources/locales/pt/lists.yml +7 -0
- data/resources/locales/pt/numbers.yml +39 -39
- data/resources/locales/pt/plurals.yml +2 -3
- data/resources/locales/pt/units.yml +110 -110
- data/resources/locales/ru/calendars.yml +213 -212
- data/resources/locales/ru/languages.yml +511 -511
- data/resources/locales/ru/layout.yml +5 -0
- data/resources/locales/ru/lists.yml +7 -0
- data/resources/locales/ru/numbers.yml +40 -40
- data/resources/locales/ru/plurals.yml +2 -5
- data/resources/locales/ru/units.yml +192 -192
- data/resources/locales/sv/calendars.yml +85 -85
- data/resources/locales/sv/languages.yml +108 -108
- data/resources/locales/sv/layout.yml +5 -0
- data/resources/locales/sv/lists.yml +7 -0
- data/resources/locales/sv/numbers.yml +39 -39
- data/resources/locales/sv/plurals.yml +2 -3
- data/resources/locales/sv/units.yml +116 -116
- data/resources/locales/th/calendars.yml +172 -171
- data/resources/locales/th/languages.yml +510 -510
- data/resources/locales/th/layout.yml +5 -0
- data/resources/locales/th/lists.yml +7 -0
- data/resources/locales/th/numbers.yml +38 -38
- data/resources/locales/th/plurals.yml +2 -3
- data/resources/locales/th/units.yml +107 -107
- data/resources/locales/tr/calendars.yml +117 -116
- data/resources/locales/tr/languages.yml +143 -143
- data/resources/locales/tr/layout.yml +5 -0
- data/resources/locales/tr/lists.yml +7 -0
- data/resources/locales/tr/numbers.yml +37 -37
- data/resources/locales/tr/plurals.yml +2 -3
- data/resources/locales/tr/units.yml +98 -98
- data/resources/locales/uk/calendars.yml +187 -186
- data/resources/locales/uk/languages.yml +520 -520
- data/resources/locales/uk/layout.yml +5 -0
- data/resources/locales/uk/lists.yml +7 -0
- data/resources/locales/uk/numbers.yml +44 -44
- data/resources/locales/uk/plurals.yml +2 -5
- data/resources/locales/uk/units.yml +192 -192
- data/resources/locales/ur/calendars.yml +112 -111
- data/resources/locales/ur/languages.yml +164 -164
- data/resources/locales/ur/layout.yml +5 -0
- data/resources/locales/ur/lists.yml +7 -0
- data/resources/locales/ur/numbers.yml +27 -27
- data/resources/locales/ur/plurals.yml +2 -3
- data/resources/locales/ur/units.yml +136 -136
- data/resources/locales/zh/calendars.yml +212 -211
- data/resources/locales/zh/languages.yml +506 -506
- data/resources/locales/zh/layout.yml +5 -0
- data/resources/locales/zh/lists.yml +7 -0
- data/resources/locales/zh/numbers.yml +37 -37
- data/resources/locales/zh/plurals.yml +2 -3
- data/resources/locales/zh/units.yml +108 -108
- data/resources/locales/zh-Hant/calendars.yml +159 -158
- data/resources/locales/zh-Hant/languages.yml +510 -510
- data/resources/locales/zh-Hant/layout.yml +5 -0
- data/resources/locales/zh-Hant/lists.yml +7 -0
- data/resources/locales/zh-Hant/numbers.yml +38 -38
- data/resources/locales/zh-Hant/plurals.yml +2 -3
- data/resources/locales/zh-Hant/units.yml +108 -108
- data/spec/bidi/bidi_spec.rb +72 -0
- data/spec/bidi/classpath_bidi_test.txt +217202 -0
- data/spec/collation/tailoring_tests/da.txt +1 -1
- data/spec/collation/tailoring_tests/fi.txt +1 -7
- data/spec/collation/tailoring_tests/zh-Hant.txt +1 -1
- data/spec/formatters/list_formatter_spec.rb +119 -0
- data/spec/localized/localized_array_spec.rb +28 -0
- data/spec/localized/localized_hash_spec.rb +22 -0
- data/spec/localized/localized_number_spec.rb +3 -3
- data/spec/localized/localized_string_spec.rb +52 -1
- data/spec/localized/localized_symbol_spec.rb +7 -0
- data/spec/normalization/base_spec.rb +2 -4
- data/spec/shared/languages_spec.rb +21 -0
- data/spec/shared/numbers_spec.rb +4 -4
- data/spec/spec_helper.rb +3 -1
- data/spec/utils/yaml/t.gif +0 -0
- data/spec/utils/yaml/t.yaml +5 -0
- data/spec/utils/yaml/yaml_spec.rb +426 -0
- 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)
|
data/lib/twitter_cldr/shared.rb
CHANGED