worldwide 1.25.6 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci-typescript.yml +1 -1
- data/.github/workflows/ci.yml +2 -2
- data/.github/workflows/npm-release.yml +1 -1
- data/.rubocop.yml +3 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +62 -53
- data/README.md +28 -0
- data/lib/worldwide/address.rb +8 -10
- data/lib/worldwide/address_validator.rb +1 -0
- data/lib/worldwide/business_names.rb +48 -0
- data/lib/worldwide/cldr/date_format_pattern.rb +6 -6
- data/lib/worldwide/cldr/fallbacks.rb +1 -1
- data/lib/worldwide/config.rb +1 -1
- data/lib/worldwide/currency.rb +4 -4
- data/lib/worldwide/extant_outcodes.rb +1 -0
- data/lib/worldwide/fields.rb +1 -0
- data/lib/worldwide/lists.rb +1 -0
- data/lib/worldwide/locale.rb +3 -3
- data/lib/worldwide/names.rb +38 -0
- data/lib/worldwide/phone.rb +0 -1
- data/lib/worldwide/region.rb +7 -7
- data/lib/worldwide/regions.rb +1 -0
- data/lib/worldwide/regions_loader.rb +0 -2
- data/lib/worldwide/version.rb +1 -1
- data/lib/worldwide/zip.rb +5 -5
- data/lib/worldwide.rb +5 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60cb3f293340533a39f8316ec7dbc1fe4dfb35483f2603cf348240db5c34ae8c
|
|
4
|
+
data.tar.gz: 74fc4ebce8fc936e6f0c80c5fab79a6c7d8534c5a4aae289a0784b2a9f9ebee1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e347d426de7e52e23504e3632a8fb4ad3e3473994138f2506859696e78b04e6ceaf2bbbab9074d34c2cbcc0828427227d2ff9eea630b97aafa2ddd5379a66be
|
|
7
|
+
data.tar.gz: 7107f99efa3ca3a9532585f69cfee927b619988bedb31f470bf46fc6b05b6ec28ba7a9f1ac2aa8fc1246922b29c83d7ba9a3ca8168c396fbd371d9cd954a814b
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
working-directory: lang/typescript
|
|
16
16
|
steps:
|
|
17
17
|
- name: Check out code
|
|
18
|
-
uses: actions/checkout@
|
|
18
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
19
19
|
- name: Setup Node
|
|
20
20
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
21
21
|
with:
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -20,9 +20,9 @@ jobs:
|
|
|
20
20
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
21
21
|
steps:
|
|
22
22
|
- name: Check out code
|
|
23
|
-
uses: actions/checkout@
|
|
23
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
24
|
- name: Set up Ruby ${{ matrix.ruby }}
|
|
25
|
-
uses: ruby/setup-ruby@
|
|
25
|
+
uses: ruby/setup-ruby@a30dfa457ad68707b8b910ac3a244714b61c0626 # v1.320.0
|
|
26
26
|
with:
|
|
27
27
|
ruby-version: ${{ matrix.ruby }}
|
|
28
28
|
bundler-cache: true
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
working-directory: lang/typescript
|
|
21
21
|
steps:
|
|
22
22
|
- name: Checkout Repo
|
|
23
|
-
uses: actions/checkout@
|
|
23
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
24
|
with:
|
|
25
25
|
token: ${{ secrets.SHOPIFY_GH_ACCESS_TOKEN }}
|
|
26
26
|
- name: Setup Node
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
+
## [1.26.0] - 2026-07-22
|
|
33
|
+
- Add `Worldwide::BusinessNames.abbreviated` for script-aware abbreviation of a single business name string. [#538](https://github.com/Shopify/worldwide/pull/538) [#553](https://github.com/Shopify/worldwide/pull/553)
|
|
34
|
+
- Add `Worldwide::Names.abbreviated` to abbreviate personal names by script. [#539](https://github.com/Shopify/worldwide/pull/539)
|
|
35
|
+
- Fix trailing whitespace in formatted Japanese addresses when the postal code is blank or excluded. [#548](https://github.com/Shopify/worldwide/pull/548)
|
|
36
|
+
- Fix `Address#format` dropping backslash sequences (e.g. `\2`) in field values. [#533](https://github.com/Shopify/worldwide/pull/533)
|
|
37
|
+
|
|
32
38
|
## [1.25.6] - 2026-07-21
|
|
33
39
|
- Bump i18n from 1.14.1 to 1.15.2 (now required as `>= 1.15`) and update `Cldr.with_cldr` to mirror i18n's fiber-aware config and fallbacks storage so the CLDR config still applies on Ruby 3.2+. [#540](https://github.com/Shopify/worldwide/pull/540)
|
|
34
40
|
|
data/Gemfile
CHANGED
|
@@ -9,7 +9,7 @@ gem "ruby-cldr", git: "https://github.com/ruby-i18n/ruby-cldr.git", ref: "86a5d7
|
|
|
9
9
|
# Specify your gem's dependencies in worldwide.gemspec
|
|
10
10
|
gemspec
|
|
11
11
|
|
|
12
|
-
gem "rake", "~> 13.
|
|
12
|
+
gem "rake", "~> 13.4"
|
|
13
13
|
|
|
14
14
|
group :development do
|
|
15
15
|
gem "minitest-focus", require: false
|
|
@@ -24,7 +24,7 @@ group :development do
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
group :test do
|
|
27
|
-
gem "minitest", "~> 5.
|
|
27
|
+
gem "minitest", "~> 5.27"
|
|
28
28
|
gem "minitest-reporters"
|
|
29
29
|
gem "mocha"
|
|
30
30
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -13,7 +13,7 @@ GIT
|
|
|
13
13
|
PATH
|
|
14
14
|
remote: .
|
|
15
15
|
specs:
|
|
16
|
-
worldwide (1.
|
|
16
|
+
worldwide (1.26.0)
|
|
17
17
|
activesupport (>= 7.0)
|
|
18
18
|
i18n (>= 1.15)
|
|
19
19
|
phonelib (~> 0.8)
|
|
@@ -21,94 +21,100 @@ PATH
|
|
|
21
21
|
GEM
|
|
22
22
|
remote: https://rubygems.org/
|
|
23
23
|
specs:
|
|
24
|
-
activesupport (7.
|
|
24
|
+
activesupport (7.2.3.1)
|
|
25
25
|
base64
|
|
26
|
+
benchmark (>= 0.3)
|
|
26
27
|
bigdecimal
|
|
27
|
-
concurrent-ruby (~> 1.0, >= 1.
|
|
28
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
28
29
|
connection_pool (>= 2.2.5)
|
|
29
30
|
drb
|
|
30
31
|
i18n (>= 1.6, < 2)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
logger (>= 1.4.2)
|
|
33
|
+
minitest (>= 5.1, < 6)
|
|
34
|
+
securerandom (>= 0.3)
|
|
35
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
36
|
+
ansi (1.6.0)
|
|
37
|
+
ast (2.4.3)
|
|
38
|
+
base64 (0.3.0)
|
|
39
|
+
benchmark (0.5.0)
|
|
40
|
+
bigdecimal (4.1.2)
|
|
41
|
+
builder (3.3.0)
|
|
42
|
+
byebug (12.0.0)
|
|
40
43
|
coderay (1.1.3)
|
|
41
|
-
concurrent-ruby (1.3.
|
|
42
|
-
connection_pool (2.
|
|
43
|
-
drb (2.
|
|
44
|
-
ruby2_keywords
|
|
44
|
+
concurrent-ruby (1.3.8)
|
|
45
|
+
connection_pool (2.5.5)
|
|
46
|
+
drb (2.2.3)
|
|
45
47
|
i18n (1.15.2)
|
|
46
48
|
concurrent-ruby (~> 1.0)
|
|
47
|
-
json (2.
|
|
49
|
+
json (2.21.1)
|
|
48
50
|
language_server-protocol (3.17.0.6)
|
|
51
|
+
lint_roller (1.1.0)
|
|
49
52
|
logger (1.7.0)
|
|
50
53
|
method_source (1.1.0)
|
|
51
|
-
minitest (5.
|
|
52
|
-
minitest-focus (1.
|
|
53
|
-
minitest (
|
|
54
|
-
minitest-reporters (1.
|
|
54
|
+
minitest (5.27.0)
|
|
55
|
+
minitest-focus (1.4.1)
|
|
56
|
+
minitest (> 5.0)
|
|
57
|
+
minitest-reporters (1.8.0)
|
|
55
58
|
ansi
|
|
56
59
|
builder
|
|
57
|
-
minitest (>= 5.0)
|
|
60
|
+
minitest (>= 5.0, < 7)
|
|
58
61
|
ruby-progressbar
|
|
59
62
|
mocha (3.1.0)
|
|
60
63
|
ruby2_keywords (>= 0.0.5)
|
|
61
|
-
mutex_m (0.1.2)
|
|
62
64
|
nokogiri (1.19.3-arm64-darwin)
|
|
63
65
|
racc (~> 1.4)
|
|
64
66
|
nokogiri (1.19.3-x86_64-linux-gnu)
|
|
65
67
|
racc (~> 1.4)
|
|
66
|
-
parallel (1.
|
|
67
|
-
parser (3.3.0
|
|
68
|
+
parallel (1.28.0)
|
|
69
|
+
parser (3.3.12.0)
|
|
68
70
|
ast (~> 2.4.1)
|
|
69
71
|
racc
|
|
70
72
|
phonelib (0.10.22)
|
|
71
73
|
prism (1.9.0)
|
|
72
|
-
pry (0.
|
|
74
|
+
pry (0.15.2)
|
|
73
75
|
coderay (~> 1.1)
|
|
74
76
|
method_source (~> 1.0)
|
|
75
|
-
pry-byebug (3.
|
|
76
|
-
byebug (~>
|
|
77
|
-
pry (>= 0.13, < 0.
|
|
77
|
+
pry-byebug (3.11.0)
|
|
78
|
+
byebug (~> 12.0)
|
|
79
|
+
pry (>= 0.13, < 0.16)
|
|
78
80
|
psych (5.1.0)
|
|
79
81
|
stringio
|
|
80
82
|
racc (1.8.1)
|
|
81
83
|
rainbow (3.1.1)
|
|
82
|
-
rake (13.
|
|
84
|
+
rake (13.4.2)
|
|
83
85
|
rake-compiler (1.3.1)
|
|
84
86
|
rake
|
|
85
87
|
rbs (3.10.4)
|
|
86
88
|
logger
|
|
87
89
|
tsort
|
|
88
|
-
regexp_parser (2.
|
|
89
|
-
|
|
90
|
-
rubocop (1.62.1)
|
|
90
|
+
regexp_parser (2.12.0)
|
|
91
|
+
rubocop (1.88.2)
|
|
91
92
|
json (~> 2.3)
|
|
92
|
-
language_server-protocol (
|
|
93
|
-
|
|
93
|
+
language_server-protocol (~> 3.17.0.2)
|
|
94
|
+
lint_roller (~> 1.1.0)
|
|
95
|
+
parallel (>= 1.10)
|
|
94
96
|
parser (>= 3.3.0.2)
|
|
95
97
|
rainbow (>= 2.2.2, < 4.0)
|
|
96
|
-
regexp_parser (>=
|
|
97
|
-
|
|
98
|
-
rubocop-ast (>= 1.31.1, < 2.0)
|
|
98
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
99
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
99
100
|
ruby-progressbar (~> 1.7)
|
|
100
|
-
unicode-display_width (>= 2.4.0, <
|
|
101
|
-
rubocop-ast (1.
|
|
102
|
-
parser (>= 3.3.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
rubocop (>= 1.
|
|
107
|
-
rubocop-ast (>=
|
|
108
|
-
rubocop-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
rubocop (
|
|
101
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
102
|
+
rubocop-ast (1.50.0)
|
|
103
|
+
parser (>= 3.3.7.2)
|
|
104
|
+
prism (~> 1.7)
|
|
105
|
+
rubocop-minitest (0.40.0)
|
|
106
|
+
lint_roller (~> 1.1)
|
|
107
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
108
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
|
109
|
+
rubocop-performance (1.26.1)
|
|
110
|
+
lint_roller (~> 1.1)
|
|
111
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
112
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
113
|
+
rubocop-rake (0.7.1)
|
|
114
|
+
lint_roller (~> 1.1)
|
|
115
|
+
rubocop (>= 1.72.1)
|
|
116
|
+
rubocop-shopify (2.18.0)
|
|
117
|
+
rubocop (~> 1.62)
|
|
112
118
|
ruby-lsp (0.26.10)
|
|
113
119
|
language_server-protocol (~> 3.17.0)
|
|
114
120
|
prism (>= 1.2, < 2.0)
|
|
@@ -116,12 +122,15 @@ GEM
|
|
|
116
122
|
ruby-progressbar (1.13.0)
|
|
117
123
|
ruby2_keywords (0.0.5)
|
|
118
124
|
rubyzip (2.3.2)
|
|
125
|
+
securerandom (0.4.1)
|
|
119
126
|
stringio (3.1.0)
|
|
120
127
|
thor (1.2.1)
|
|
121
128
|
tsort (0.2.0)
|
|
122
129
|
tzinfo (2.0.6)
|
|
123
130
|
concurrent-ruby (~> 1.0)
|
|
124
|
-
unicode-display_width (2.
|
|
131
|
+
unicode-display_width (3.2.0)
|
|
132
|
+
unicode-emoji (~> 4.1)
|
|
133
|
+
unicode-emoji (4.2.0)
|
|
125
134
|
|
|
126
135
|
PLATFORMS
|
|
127
136
|
arm64-darwin-21
|
|
@@ -131,12 +140,12 @@ PLATFORMS
|
|
|
131
140
|
x86_64-linux
|
|
132
141
|
|
|
133
142
|
DEPENDENCIES
|
|
134
|
-
minitest (~> 5.
|
|
143
|
+
minitest (~> 5.27)
|
|
135
144
|
minitest-focus
|
|
136
145
|
minitest-reporters
|
|
137
146
|
mocha
|
|
138
147
|
pry-byebug
|
|
139
|
-
rake (~> 13.
|
|
148
|
+
rake (~> 13.4)
|
|
140
149
|
rake-compiler
|
|
141
150
|
rubocop
|
|
142
151
|
rubocop-minitest
|
data/README.md
CHANGED
|
@@ -91,6 +91,7 @@ Here the list of the features we currently support:
|
|
|
91
91
|
- [🕰 Localized Timezone](#--localized-timezone)
|
|
92
92
|
- [➡🕰 Map Deprecated Timezone Name to Modern Name](#--map-deprecated-timezone-name-to-modern-name)
|
|
93
93
|
- [👥 Names](#--names)
|
|
94
|
+
- [🏢 Business names](#-business-names)
|
|
94
95
|
- [👥 Lists](#--lists)
|
|
95
96
|
- [❣️ Punctuation](#️---punctuation)
|
|
96
97
|
- [🤑 Currency support](#--currency-support)
|
|
@@ -625,6 +626,8 @@ Say, for example, your customer has the given name "Ken" and surname "Tanaka".
|
|
|
625
626
|
|
|
626
627
|
`Names.surname_first?` will let you know if the current locale places the surname (family name, last name) before the given name ("first name", forename).
|
|
627
628
|
|
|
629
|
+
`Names.abbreviated` returns a short form of a personal name based on its writing script. Latin names use the first letters of the given name and surname. Han, Hiragana, and Katakana names use the surname. Hangul names use the given name when it is within `ideal_max_length`, or its first grapheme cluster when it is longer. Thai names use the first grapheme cluster of the given name. The Hangul and Thai rules fall back to the surname when the given name is blank. The method returns `nil` when it cannot abbreviate the name, allowing the caller to fall back to `Names.greeting`.
|
|
630
|
+
|
|
628
631
|
```ruby
|
|
629
632
|
I18n.with_locale(:en) { Worldwide.names.full(given: "John", surname: "Smith") }
|
|
630
633
|
=> "John Smith"
|
|
@@ -636,12 +639,37 @@ I18n.with_locale(:en) { Worldwide.names.greeting(given: "John", surname: "Smith"
|
|
|
636
639
|
=> "John"
|
|
637
640
|
I18n.with_locale(:ja) { Worldwide.names.greeting(given: "John", surname: "Smith") }
|
|
638
641
|
=> "Smith様"
|
|
642
|
+
Worldwide.names.abbreviated(given: "John", surname: "Smith")
|
|
643
|
+
=> "JS"
|
|
644
|
+
Worldwide.names.abbreviated(given: "이슬", surname: "재현", ideal_max_length: 1)
|
|
645
|
+
=> "이"
|
|
639
646
|
Worldwide.names.surname_first?("en")
|
|
640
647
|
=> false
|
|
641
648
|
Worldwide.names.surname_first?("ja")
|
|
642
649
|
=> true
|
|
643
650
|
```
|
|
644
651
|
|
|
652
|
+
### 🏢 Business names
|
|
653
|
+
|
|
654
|
+
`Worldwide::BusinessNames` abbreviates a single business name according to its detected script. The default `ideal_max_length` is 3. The method returns `nil` when the input is blank, uses multiple or unsupported scripts, or cannot be abbreviated by the script's rules. It is also available through `Worldwide.business_names`.
|
|
655
|
+
|
|
656
|
+
```ruby
|
|
657
|
+
Worldwide.business_names.abbreviated(name: "Shopify")
|
|
658
|
+
=> "Sho"
|
|
659
|
+
Worldwide::BusinessNames.abbreviated(name: "A Better Shop")
|
|
660
|
+
=> "ABS"
|
|
661
|
+
Worldwide::BusinessNames.abbreviated(name: "A Better Looking Shop")
|
|
662
|
+
=> "AS"
|
|
663
|
+
Worldwide::BusinessNames.abbreviated(name: "삼성 한국어", ideal_max_length: 2)
|
|
664
|
+
=> "삼성"
|
|
665
|
+
Worldwide::BusinessNames.abbreviated(name: "任天堂")
|
|
666
|
+
=> "任天堂"
|
|
667
|
+
Worldwide::BusinessNames.abbreviated(name: "อภัADSยวงศ์")
|
|
668
|
+
=> nil
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Latin names use the first grapheme clusters of one word, the initials of up to `ideal_max_length` words, or the initials of the first and last words when there are more words. Hangul names use the first `ideal_max_length` grapheme clusters of the first word. Thai names without spaces use the first grapheme cluster. Han, Katakana, and Hiragana names without spaces are returned in full. Thai, Han, Katakana, and Hiragana names with spaces return `nil`.
|
|
672
|
+
|
|
645
673
|
### 👥 Lists
|
|
646
674
|
|
|
647
675
|
This module will offer you a way to display a list while respecting locale preferences.
|
data/lib/worldwide/address.rb
CHANGED
|
@@ -296,7 +296,7 @@ module Worldwide
|
|
|
296
296
|
result << line unless blank?(line.join)
|
|
297
297
|
end
|
|
298
298
|
|
|
299
|
-
result + additional_lines.
|
|
299
|
+
result + additional_lines.zip
|
|
300
300
|
end
|
|
301
301
|
|
|
302
302
|
# Returns a hash containing the values for each address field
|
|
@@ -343,7 +343,7 @@ module Worldwide
|
|
|
343
343
|
|
|
344
344
|
replacement ||= ""
|
|
345
345
|
|
|
346
|
-
mapped = mapped.gsub("{#{snake_to_camel_case(key)}}"
|
|
346
|
+
mapped = mapped.gsub("{#{snake_to_camel_case(key)}}") { replacement }
|
|
347
347
|
end
|
|
348
348
|
mapped
|
|
349
349
|
end
|
|
@@ -354,7 +354,7 @@ module Worldwide
|
|
|
354
354
|
def japan_with_non_japanese_script?
|
|
355
355
|
text = build_formatted_address_data.values.join
|
|
356
356
|
|
|
357
|
-
country_code == "JP" && Worldwide::Scripts.identify(text: text).
|
|
357
|
+
country_code == "JP" && !Worldwide::Scripts.identify(text: text).intersect?(JAPANESE_SCRIPTS)
|
|
358
358
|
end
|
|
359
359
|
|
|
360
360
|
def normalize_city
|
|
@@ -446,13 +446,11 @@ module Worldwide
|
|
|
446
446
|
def strip_extra_chars(lines:, excluded_fields:)
|
|
447
447
|
result = []
|
|
448
448
|
lines.each do |components|
|
|
449
|
-
line = components
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
line = strip_extra_japanese_chars(line: line, excluded_fields: excluded_fields)
|
|
449
|
+
line = strip_extra_japanese_chars(line: components, excluded_fields: excluded_fields)
|
|
450
|
+
line.map!(&:strip)
|
|
451
|
+
line.reject!(&:empty?)
|
|
454
452
|
|
|
455
|
-
result << line
|
|
453
|
+
result << line unless blank?(line.join(""))
|
|
456
454
|
end
|
|
457
455
|
result
|
|
458
456
|
end
|
|
@@ -463,7 +461,7 @@ module Worldwide
|
|
|
463
461
|
# - `〒` ("yuubin" mark) is a prefix that's prepended to the postal code (zip)
|
|
464
462
|
# If the associated field is excluded/empty, we need to suppress the associated special character.
|
|
465
463
|
def strip_extra_japanese_chars(line:, excluded_fields:)
|
|
466
|
-
return
|
|
464
|
+
return if line.nil?
|
|
467
465
|
|
|
468
466
|
line.map do |field|
|
|
469
467
|
stripped = field
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Worldwide
|
|
4
|
+
class BusinessNames
|
|
5
|
+
class << self
|
|
6
|
+
# Returns a script aware abbreviation, or nil when the name cannot be abbreviated.
|
|
7
|
+
def abbreviated(name:, ideal_max_length: 3)
|
|
8
|
+
name_stripped = name&.strip
|
|
9
|
+
|
|
10
|
+
return if Util.blank?(name_stripped)
|
|
11
|
+
return unless ideal_max_length.is_a?(Integer) && ideal_max_length.positive?
|
|
12
|
+
|
|
13
|
+
scripts = Scripts.identify(text: name_stripped)
|
|
14
|
+
return unless scripts.one?
|
|
15
|
+
|
|
16
|
+
case scripts.first
|
|
17
|
+
when :Latin
|
|
18
|
+
latin_abbreviation(name_stripped, ideal_max_length)
|
|
19
|
+
when :Hangul
|
|
20
|
+
name_stripped.split(" ", 2).first.grapheme_clusters[0, ideal_max_length].join
|
|
21
|
+
when :Thai
|
|
22
|
+
# Thai does not use spaces between words.
|
|
23
|
+
return if name_stripped.include?(" ")
|
|
24
|
+
|
|
25
|
+
name_stripped.grapheme_clusters.first
|
|
26
|
+
when :Han, :Katakana, :Hiragana
|
|
27
|
+
return if name_stripped.include?(" ")
|
|
28
|
+
|
|
29
|
+
name_stripped
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def latin_abbreviation(name, ideal_max_length)
|
|
36
|
+
words = name.split(" ")
|
|
37
|
+
|
|
38
|
+
if words.length == 1
|
|
39
|
+
words.first.grapheme_clusters[0, ideal_max_length].join
|
|
40
|
+
elsif words.length <= ideal_max_length
|
|
41
|
+
words.map { |word| word.grapheme_clusters.first }.join
|
|
42
|
+
else
|
|
43
|
+
words.first.grapheme_clusters.first + words.last.grapheme_clusters.first
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -42,36 +42,36 @@ module Worldwide
|
|
|
42
42
|
tokens
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
private
|
|
46
|
-
|
|
47
45
|
PATTERN_FIELD = /([a-zA-Z])\1*/
|
|
48
46
|
SINGLE_QUOTE_LITERAL = /''/
|
|
49
47
|
QUOTED_LITERAL = /'(([^']|#{SINGLE_QUOTE_LITERAL})*[^'])'/
|
|
50
48
|
UNQUOTED_LITERAL = /[^a-zA-Z']+/
|
|
51
49
|
|
|
50
|
+
private
|
|
51
|
+
|
|
52
52
|
def parse_field(format)
|
|
53
|
-
return
|
|
53
|
+
return unless format.start_with?(PATTERN_FIELD)
|
|
54
54
|
|
|
55
55
|
match = PATTERN_FIELD.match(format)
|
|
56
56
|
[Field.from(match[0]), match.end(0)]
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def parse_single_quote(format)
|
|
60
|
-
return
|
|
60
|
+
return unless format.start_with?(SINGLE_QUOTE_LITERAL)
|
|
61
61
|
|
|
62
62
|
match = SINGLE_QUOTE_LITERAL.match(format)
|
|
63
63
|
[Literal.new("'"), match.end(0)]
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def parse_quoted_literal(format)
|
|
67
|
-
return
|
|
67
|
+
return unless format.start_with?(QUOTED_LITERAL)
|
|
68
68
|
|
|
69
69
|
match = QUOTED_LITERAL.match(format)
|
|
70
70
|
[Literal.new(match[1].gsub(SINGLE_QUOTE_LITERAL, "'")), match.end(0)]
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def parse_unquoted_literal(format)
|
|
74
|
-
return
|
|
74
|
+
return unless format.start_with?(UNQUOTED_LITERAL)
|
|
75
75
|
|
|
76
76
|
match = UNQUOTED_LITERAL.match(format)
|
|
77
77
|
[Literal.new(match[0]), match.end(0)]
|
|
@@ -38,7 +38,7 @@ module Worldwide
|
|
|
38
38
|
loop do
|
|
39
39
|
if cldr_defined_parents[ancestors.last]
|
|
40
40
|
ancestors << cldr_defined_parents[ancestors.last]
|
|
41
|
-
elsif I18n::Locale::Tag.tag(ancestors.last).parents.
|
|
41
|
+
elsif I18n::Locale::Tag.tag(ancestors.last).parents.any?
|
|
42
42
|
ancestors << I18n::Locale::Tag.tag(ancestors.last).parents.first.to_sym
|
|
43
43
|
else
|
|
44
44
|
break
|
data/lib/worldwide/config.rb
CHANGED
|
@@ -70,7 +70,7 @@ module Worldwide
|
|
|
70
70
|
# we don't want to trigger the backend resolution until after we've determined whether they have set it explicitly.
|
|
71
71
|
class_variable = "@@#{key}".to_sym
|
|
72
72
|
instance_variable = "@#{key}".to_sym
|
|
73
|
-
i18n_config.class.
|
|
73
|
+
i18n_config.class.class_variable_defined?(class_variable) || i18n_config.instance_variables.include?(instance_variable)
|
|
74
74
|
else
|
|
75
75
|
i18n_config.key?(key)
|
|
76
76
|
end
|
data/lib/worldwide/currency.rb
CHANGED
|
@@ -117,7 +117,7 @@ module Worldwide
|
|
|
117
117
|
raw_symbol = Worldwide::Cldr.t("currencies.#{@currency_code}.narrow_symbol", default: nil, locale: locale) ||
|
|
118
118
|
Worldwide::Cldr.t("currencies.#{@currency_code}.symbol", default: nil, locale: locale)
|
|
119
119
|
|
|
120
|
-
return
|
|
120
|
+
return if raw_symbol.nil?
|
|
121
121
|
|
|
122
122
|
# For some locales (e.g., HK), in-market folks have requested that we leave the CLDR behaviour untouched
|
|
123
123
|
exceptional_symbol = EXCEPTIONS.fetch(@currency_code.to_sym, nil)
|
|
@@ -154,7 +154,7 @@ module Worldwide
|
|
|
154
154
|
private
|
|
155
155
|
|
|
156
156
|
def combine(amount:, decimal_places:, humanize:, locale:, symbol:)
|
|
157
|
-
space = if has_space(locale)
|
|
157
|
+
space = if has_space?(locale)
|
|
158
158
|
# This is U+00A0, the Unicode non-breaking space character
|
|
159
159
|
[160].pack("U*")
|
|
160
160
|
else
|
|
@@ -237,7 +237,7 @@ module Worldwide
|
|
|
237
237
|
end
|
|
238
238
|
|
|
239
239
|
# Returns true if there should be a space between the amount and the currency symbol
|
|
240
|
-
def has_space(locale)
|
|
240
|
+
def has_space?(locale)
|
|
241
241
|
pattern = Worldwide::Cldr.t("numbers.latn.formats.currency.patterns.default.standard", locale: locale)
|
|
242
242
|
|
|
243
243
|
# Note that CLDR uses these characters in its currency formats:
|
|
@@ -250,7 +250,7 @@ module Worldwide
|
|
|
250
250
|
def minor_symbol
|
|
251
251
|
key = @currency_code
|
|
252
252
|
|
|
253
|
-
return
|
|
253
|
+
return unless Currency.minor_symbols.key?(key)
|
|
254
254
|
|
|
255
255
|
Currency.minor_symbols[key]["symbol"]
|
|
256
256
|
end
|
data/lib/worldwide/fields.rb
CHANGED
data/lib/worldwide/lists.rb
CHANGED
data/lib/worldwide/locale.rb
CHANGED
|
@@ -71,7 +71,7 @@ module Worldwide
|
|
|
71
71
|
if @name_cache[context].is_a?(I18n::MissingTranslation)
|
|
72
72
|
raise @name_cache[context] if throw
|
|
73
73
|
|
|
74
|
-
return
|
|
74
|
+
return
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
@name_cache[context]
|
|
@@ -93,7 +93,7 @@ module Worldwide
|
|
|
93
93
|
if @endonym.is_a?(I18n::MissingTranslation)
|
|
94
94
|
raise @endonym if throw
|
|
95
95
|
|
|
96
|
-
return
|
|
96
|
+
return
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
@endonym
|
|
@@ -113,7 +113,7 @@ module Worldwide
|
|
|
113
113
|
result = lookup(language, locale: target_locale)
|
|
114
114
|
if result
|
|
115
115
|
transformed = Worldwide::Cldr::ContextTransforms.transform(result, :languages, context, locale: target_locale)
|
|
116
|
-
break "#{transformed}#{
|
|
116
|
+
break "#{transformed}#{territories_suffix(code.to_s) if i > 0}"
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
end
|
data/lib/worldwide/names.rb
CHANGED
|
@@ -30,6 +30,44 @@ module Worldwide
|
|
|
30
30
|
names.map { |name| name[0] }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def abbreviated(given:, surname:, ideal_max_length: 3)
|
|
34
|
+
given_stripped = given&.strip
|
|
35
|
+
surname_stripped = surname&.strip
|
|
36
|
+
|
|
37
|
+
combined_name = given_stripped.to_s + surname_stripped.to_s
|
|
38
|
+
return if combined_name.blank? || combined_name.match?(/[\p{Punctuation}\s]/)
|
|
39
|
+
return unless ideal_max_length.is_a?(Integer) && ideal_max_length.positive?
|
|
40
|
+
|
|
41
|
+
scripts = Scripts.identify(text: combined_name)
|
|
42
|
+
return unless scripts.length == 1
|
|
43
|
+
|
|
44
|
+
given_clusters = given_stripped&.grapheme_clusters
|
|
45
|
+
surname_clusters = surname_stripped&.grapheme_clusters
|
|
46
|
+
|
|
47
|
+
# Scripts that Scripts.identify recognizes but that have no abbreviation rule
|
|
48
|
+
# here (e.g. Arabic) intentionally return nil so callers fall back to a greeting.
|
|
49
|
+
case scripts.first
|
|
50
|
+
when :Latin
|
|
51
|
+
[given_stripped, surname_stripped].reject(&:blank?).map { |name| name[0] }.join
|
|
52
|
+
when :Han, :Katakana, :Hiragana
|
|
53
|
+
surname_stripped.presence
|
|
54
|
+
when :Hangul
|
|
55
|
+
if given_stripped.blank?
|
|
56
|
+
surname_stripped
|
|
57
|
+
elsif given_clusters.length > ideal_max_length
|
|
58
|
+
given_clusters[0]
|
|
59
|
+
else
|
|
60
|
+
given_stripped
|
|
61
|
+
end
|
|
62
|
+
when :Thai
|
|
63
|
+
if given_stripped.present?
|
|
64
|
+
given_clusters[0]
|
|
65
|
+
elsif surname_stripped.present?
|
|
66
|
+
surname_clusters[0]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
33
71
|
private
|
|
34
72
|
|
|
35
73
|
def format_name(format, given, surname)
|
data/lib/worldwide/phone.rb
CHANGED
data/lib/worldwide/region.rb
CHANGED
|
@@ -375,7 +375,7 @@ module Worldwide
|
|
|
375
375
|
# An Worldwide::Field that can be used to ask about the field, including
|
|
376
376
|
# labels, error messages, and an autofill value if there is one.
|
|
377
377
|
def field(key:)
|
|
378
|
-
return
|
|
378
|
+
return unless country?
|
|
379
379
|
|
|
380
380
|
Worldwide::Fields.field(country_code: iso_code, field_key: key)
|
|
381
381
|
end
|
|
@@ -479,7 +479,7 @@ module Worldwide
|
|
|
479
479
|
#
|
|
480
480
|
# @return [String, nil] One of "ALPHANUMERIC", "NUMERIC", "NUMERIC_AND_PUNCTUATION", or nil if no zip_example
|
|
481
481
|
def zip_type
|
|
482
|
-
return
|
|
482
|
+
return if zip_example.nil?
|
|
483
483
|
|
|
484
484
|
if zip_example.match?(/[A-Za-z]/)
|
|
485
485
|
FORMAT_TYPES[:ALPHANUMERIC]
|
|
@@ -554,7 +554,7 @@ module Worldwide
|
|
|
554
554
|
field ? !!field["required"] : false
|
|
555
555
|
end
|
|
556
556
|
|
|
557
|
-
def answers_to_cldr_code(search_code)
|
|
557
|
+
def answers_to_cldr_code?(search_code)
|
|
558
558
|
return false if Util.blank?(search_code) || Util.blank?(cldr_code)
|
|
559
559
|
return true if search_code.casecmp(cldr_code).zero?
|
|
560
560
|
|
|
@@ -562,7 +562,7 @@ module Worldwide
|
|
|
562
562
|
"#{pc&.cldr_code&.downcase}#{cldr_code.downcase}" == search_code.downcase
|
|
563
563
|
end
|
|
564
564
|
|
|
565
|
-
def answers_to_iso_code(search_code)
|
|
565
|
+
def answers_to_iso_code?(search_code)
|
|
566
566
|
return true if search_code == iso_code
|
|
567
567
|
|
|
568
568
|
pc = parent_country
|
|
@@ -616,9 +616,9 @@ module Worldwide
|
|
|
616
616
|
#
|
|
617
617
|
# Returns the Region in which the zip belongs based on the prefix, or `nil` if no match is found.
|
|
618
618
|
def search_prefixes_by_normalized_zip(prefixes:, zip:, allow_partial_zip: false)
|
|
619
|
-
return
|
|
620
|
-
return
|
|
621
|
-
return
|
|
619
|
+
return if Worldwide::Util.blank?(prefixes)
|
|
620
|
+
return if Worldwide::Util.blank?(zip)
|
|
621
|
+
return unless allow_partial_zip || passes_country_zip_regexp?(value: zip)
|
|
622
622
|
|
|
623
623
|
stripped = Zip.strip_optional_country_prefix(country_code: iso_code, zip: zip)
|
|
624
624
|
|
data/lib/worldwide/regions.rb
CHANGED
data/lib/worldwide/version.rb
CHANGED
data/lib/worldwide/zip.rb
CHANGED
|
@@ -50,7 +50,7 @@ module Worldwide
|
|
|
50
50
|
# @param min_confidence [Integer] The minimum confidence level (between 0-100) that is accepted from a suggestion (optional)
|
|
51
51
|
# @return [Region] which is a "country" if we have a suggestion, or `nil` if we do not.
|
|
52
52
|
def find_country(country_code: nil, zip:, min_confidence: 0)
|
|
53
|
-
return
|
|
53
|
+
return unless Util.present?(zip)
|
|
54
54
|
|
|
55
55
|
country = Worldwide.region(code: country_code) unless country_code.nil?
|
|
56
56
|
return country if country&.valid_zip?(zip)
|
|
@@ -62,7 +62,7 @@ module Worldwide
|
|
|
62
62
|
return suggestion unless suggestion.nil? || confidence.nil? || confidence < min_confidence
|
|
63
63
|
|
|
64
64
|
# If our postal code is wholly numeric, we can't make an intelligent suggestion without an alleged country.
|
|
65
|
-
return
|
|
65
|
+
return unless adjusted_zip.match?(/[A-Z]/)
|
|
66
66
|
|
|
67
67
|
# Try a broader-ranging match without considering the alleged country
|
|
68
68
|
# We'll see if we have only a single suggestion and, if so, return it.
|
|
@@ -95,7 +95,7 @@ module Worldwide
|
|
|
95
95
|
return autofill if Util.present?(autofill)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
return
|
|
98
|
+
return if zip.nil?
|
|
99
99
|
|
|
100
100
|
# Convert to uppercase
|
|
101
101
|
# Convert numeric and romaji full-width to half-width
|
|
@@ -261,8 +261,6 @@ module Worldwide
|
|
|
261
261
|
end
|
|
262
262
|
end
|
|
263
263
|
|
|
264
|
-
private
|
|
265
|
-
|
|
266
264
|
# Countries that use GB-style postal code spacing, and should normalize the same way as GB
|
|
267
265
|
GB_STYLE_ZIP_COUNTRIES = ["GB", "GG", "GI", "IM", "JE"]
|
|
268
266
|
private_constant :GB_STYLE_ZIP_COUNTRIES
|
|
@@ -355,6 +353,8 @@ module Worldwide
|
|
|
355
353
|
}
|
|
356
354
|
private_constant :OPTIONAL_PREFIX_COUNTRIES
|
|
357
355
|
|
|
356
|
+
private
|
|
357
|
+
|
|
358
358
|
REQUIRED_PREFIX_COUNTRIES = {
|
|
359
359
|
VG: "VG",
|
|
360
360
|
}
|
data/lib/worldwide.rb
CHANGED
|
@@ -14,6 +14,7 @@ require "worldwide/extant_outcodes"
|
|
|
14
14
|
|
|
15
15
|
require "worldwide/address"
|
|
16
16
|
require "worldwide/address_validator"
|
|
17
|
+
require "worldwide/business_names"
|
|
17
18
|
require "worldwide/calendar"
|
|
18
19
|
require "worldwide/cldr"
|
|
19
20
|
require "worldwide/cldr/context_transforms"
|
|
@@ -54,6 +55,10 @@ module Worldwide
|
|
|
54
55
|
Address.new(**kwargs)
|
|
55
56
|
end
|
|
56
57
|
|
|
58
|
+
def business_names
|
|
59
|
+
BusinessNames
|
|
60
|
+
end
|
|
61
|
+
|
|
57
62
|
def currency(code:)
|
|
58
63
|
currency_code = code.to_s.upcase.rjust(3, "0")
|
|
59
64
|
@currencies_cache[currency_code] ||= Currency.new(code: currency_code)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: worldwide
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.26.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
@@ -8677,6 +8677,7 @@ files:
|
|
|
8677
8677
|
- lib/worldwide.rb
|
|
8678
8678
|
- lib/worldwide/address.rb
|
|
8679
8679
|
- lib/worldwide/address_validator.rb
|
|
8680
|
+
- lib/worldwide/business_names.rb
|
|
8680
8681
|
- lib/worldwide/calendar.rb
|
|
8681
8682
|
- lib/worldwide/calendar/gregorian.rb
|
|
8682
8683
|
- lib/worldwide/cldr.rb
|
|
@@ -8735,7 +8736,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
8735
8736
|
- !ruby/object:Gem::Version
|
|
8736
8737
|
version: '0'
|
|
8737
8738
|
requirements: []
|
|
8738
|
-
rubygems_version: 4.0.
|
|
8739
|
+
rubygems_version: 4.0.16
|
|
8739
8740
|
specification_version: 4
|
|
8740
8741
|
summary: Internationalization and localization APIs
|
|
8741
8742
|
test_files: []
|