Ruby 实现了 ICU (国际组件用于 Unicode),它使用通用区域数据存储库来格式化日期、复数等。
TwitterCldr uses Unicode's Common Locale Data Repository (CLDR) to format certain types of text into their localized equivalents. Currently supported types of text include dates, times, currencies, decimals, percentages, and symbols.
gem install twitter_cldr
require 'twitter_cldr'
Get a list of all currently supported locales (these are all supported on twitter.com):
TwitterCldr.supported_locales # [:af, :ar, :az, :be, :bg, :bn, ... ]
Determine if a locale is supported by TwitterCLDR:
TwitterCldr.supported_locale?(:es) # true
TwitterCldr.supported_locale?(:xx) # false
TwitterCldr patches core Ruby objects like Integer and Date to make localization as straightforward as possible.
Integer and Float objects are supported (as well as Fixnum and Bignum for Ruby versions "EUR") # "1.337,00 €"
1337.localize(:es).to_percent.to_s # "1.337 %" 1337.localize(:es).to_percent.to_s(:precision => 2) # "1.337,00 %"
1337.localize(:es).to_decimal.to_s(:precision => 3) # "1.337,000"
**Note**: The `:precision` option can be used with all these number formatters.
Behind the scenes, these convenience methods are creating instances of `LocalizedNumber`. You can do the same thing if you're feeling adventurous:
```ruby
num = TwitterCldr::Localized::LocalizedNumber.new(1337, :es)
num.to_currency.to_s # ...etc
If you're looking for a list of supported currencies, use the TwitterCldr::Shared::Currencies class:
# all supported currency codes
TwitterCldr::Shared::Currencies.currency_codes # ["ADP", "AED", "AFA", "AFN", ... ]
# data for a specific currency code
TwitterCldr::Shared::Currencies.for_code("CAD") # {:currency=>:CAD, :name=>"Canadian Dollar", :cldr_symbol=>"CA$", :symbol=>"CA$", :code_points=>[67, 65, 36]}
In addition to formatting regular decimals, TwitterCLDR supports short and long decimals. Short decimals abbreviate the notation for the appropriate power of ten, for example "1M" for 1,000,000 or "2K" for 2,000. Long decimals include the full notation, for example "1 million" or "2 thousand". Long and short decimals can be generated using the appropriate format option:
2337.localize.to_decimal.to_s(format: :short) # "2K"
1337123.localize.to_decimal.to_s(format: :short) # "1M"
2337.localize.to_decimal.to_s(format: :long) # "2 thousand"
1337123.localize.to_decimal.to_s(format: :long) # "1 million"
TwitterCLDR supports formatting numbers with an attached unit, for example "12 degrees Celsius". It's easy to make use of this functionality via the #to_unit method:
12.localize.to_unit.length_mile # "12 miles"
12.localize(:ru).to_unit.length_mile # "12 милях"
Units support a few different forms, long, short, and narrow:
12.localize.to_unit.mass_kilogram(form: :short) # "12 kg"
To get a list of all available unit types, use the #unit_types method:
unit = 12.localize.to_unit
unit.unit_types # => [:length_mile, :temperature_celsius, :mass_kilogram, ...]
TwitterCLDR's rule-based number formatters are capable of transforming integers into their written equivalents. Note that rule-based formatting of decimal numbers is currently not supported for languages other than English.
For easy spellout formatting, check out the LocalizedNumber#spellout method:
123.localize.spellout # one hundred twenty-three
25_641.localize.spellout # twenty-five thousand six hundred forty-one
As always, you can call #localize with a locale symbol:
123.localize(:es).spellout # ciento veintitrés
25_641.localize(:ru).spellout # двадцать пять тысяч шестьсот сорок один
The available rule-based number formats defined by the CLDR data set vary by language. Some languages support ordinal and cardinal numbers, occasionally with an additional masculine/feminine option, while others do not. You'll need to consult the list of available formats for your language.
Rule-based number formats are categorized by groups, and within groups by rulesets. You'll need to specify both to make use of all the available formats for your language.
To get a list of supported groups, use the #group_names method:
123.localize(:pt).rbnf.group_names # ["SpelloutRules", "OrdinalRules"]
To get a list of supported rulesets for a group name, use the #rule_set_names_for_group method:
# ["digits-ordinal-masculine", "digits-ordinal-feminine", "digits-ordinal"]
123.localize(:pt).rbnf.rule_set_names_for_group("OrdinalRules")
Once you've chosen a group and ruleset, you can pass them to the to_rbnf_s method:
123.localize(:pt).to_rbnf_s("OrdinalRules", "digits-ordinal-feminine") # 123a
123.localize(:pt).to_rbnf_s("OrdinalRules", "digits-ordinal-masculine") # 123o
For comparison, here's what English ordinal formatting looks like:
123.localize.to_rbnf_s("OrdinalRules", "digits-ordinal") # 123rd
For English (and other languages), you can also specify an ordinal spellout:
123.localize.to_rbnf_s("SpelloutRules", "spellout-ordinal") # one hundred twenty-third
123.localize(:pt).to_rbnf_s("SpelloutRules", "spellout-ordinal-masculine") # centésimo vigésimo terceiro
Time, and DateTime objects are supported. Date objects are supported transiently:
DateTime.now.localize(:es).to_full_s # "viernes, 14 de febrero de 2014, 12:20:05 (tiempo universal coordinado)"
DateTime.now.localize(:es).to_long_s # "14 de febrero de 2014, 12:20:05 UTC"
DateTime.now.localize(:es).to_medium_s # "14 feb 2014, 12:20:05"
DateTime.now.localize(:es).to_short_s # "14/2/14, 12:20"
Time.now.localize(:es).to_full_s # "12:20:05 (tiempo universal coordinado)"
Time.now.localize(:es).to_long_s # "12:20:05 UTC"
Time.now.localize(:es).to_medium_s # "12:20:05"
Time.now.localize(:es).to_short_s # "12:20"
DateTime.now.localize(:es).to_date.to_full_s # "viernes, 14 de febrero de 2014"
DateTime.now.localize(:es).to_date.to_long_s # "14 de febrero de 2014"
DateTime.now.localize(:es).to_date.to_medium_s # "14 feb 2014"
DateTime.now.localize(:es).to_date.to_short_s # "14/2/14"
The default CLDR data set only includes 4 date formats, full, long, medium, and short. See below for a list of additional formats.
Behind the scenes, these convenience methods are creating instances of LocalizedDate, LocalizedTime, and LocalizedDateTime. You can do the same thing if you're feeling adventurous:
dt = TwitterCldr::Localized::LocalizedDateTime.new(DateTime.now, :es)
dt.to_short_s # ...etc
Besides the default date formats, CLDR supports a number of additional ones. The list of available formats varies for each locale. To get a full list, use the additional_formats method:
# ["Bh", "Bhm", "Bhms", "E", "EBhm", "EBhms", "EEEEd", "EHm", "EHms", "Ed", "Ehm", "Ehms", ... ]
DateTime.now.localize(:ja).additional_formats
You can use any of the returned formats as the argument to the to_additional_s method:
# "14日金曜日"
DateTime.now.localize(:ja).to_additional_s("EEEEd")
…
ruby
(DateTime.now - 1).localize.ago.to_s # "1 day ago"
(DateTime.now - 0.5).localize.ago.to_s # "12 hours ago" (i.e. half a day)
(DateTime.now + 1).localize.until.to_s # "in 1 day"
(DateTime.now + 0.5).localize.until.to_s # "in 12 hours"
Specify other locales:
(DateTime.now - 1).localize(:de).ago.to_s # "vor 1 Tag"
(DateTime.now + 1).localize(:de).until.to_s # "in 1 Tag"
Force TwitterCLDR to use a specific time unit by including the :unit option:
(DateTime.now - 1).localize(:de).ago.to_s(:unit => :hour) # "vor 24 Stunden"
(DateTime.now + 1).localize(:de).until.to_s(:unit => :hour) # "in 24 Stunden"
Specify a different reference point for the time span calculation:
# 86400 = 1 day in seconds, 259200 = 3 days in seconds
(Time.now + 86400).localize(:de).ago(:base_time => (Time.now + 259200)).to_s(:unit => :hour) # "vor 48 Stunden"
Behind the scenes, these convenience methods are creating instances of LocalizedTimespan, whose constructor accepts a number of seconds as the first argument. You can do the same thing if you're feeling adventurous:
ts = TwitterCldr::Localized::LocalizedTimespan.new(86400, :locale => :de)
ts.to_s # "in 1 Tag"
ts.to_s(:unit => :hour) # "in 24 Stunden"
ts = TwitterCldr::Localized::LocalizedTimespan.new(-86400, :locale => :de)
ts.to_s # "vor 1 Tag"
ts.to_s(:unit => :hour) # "vor 24 Stunden"
By default, timespans are exact representations of a given unit of elapsed time. TwitterCLDR also supports approximate timespans which round up to the nearest larger unit. For example, "44 seconds" remains "44 seconds" while "45 seconds" becomes "1 minute". To approximate, pass the :approximate => true option into to_s:
TwitterCldr::Localized::LocalizedTimespan.new(44).to_s(:approximate => true) # "in 44 seconds"
TwitterCldr::Localized::LocalizedTimespan.new(45).to_s(:approximate => true) # "in 1 minute"
TwitterCldr::Localized::LocalizedTimespan.new(52).to_s(:approximate => true) # "in 1 minute"
Timezones can be specified for any instance of LocalizedTime, LocalizedDate, or LocalizedDateTime via the with_timezone function:
# "lunes, 4 de noviembre de 2019, 16:00:00 (hora estándar del Pacífico)"
DateTime.new(2019, 11, 5).localize(:es).with_timezone('America/Los_Angeles').to_full_s
…
ruby
tz = TwitterCldr::Timezones::Timezone.instance('Australia/Brisbane', :en)
A list of available timezone formats can be retrieved like so:
TwitterCldr::Timezones::Timezone::ALL_FORMATS
Format a timezone by calling the #display_name_for method:
# "Brisbane Time"
tz.display_name_for(DateTime.new(2019, 11, 5), :generic_location)
# "Australian Eastern Standard Time"
tz.display_name_for(DateTime.new(2019, 11, 5), :generic_long)
#display_name_for also accepts arguments for resolving ambiguous times. See TZInfo Documentation for more information.
CLDR contains a trove of calendar data, much of which can be accessed. One example is names of months, days, years.
TwitterCldr::Shared::Calendar.new(:sv).months.take(3) # ["januari", "februari", "mars"]
TwitterCLDR supports formatting lists of strings as you might do in English by using commas, eg: "Apples, cherries, and oranges". Use the localize method on an array followed by a call to to_sentence:
["apples", "cherries", "oranges"].localize.to_sentence # "apples, cherries, and oranges"
["apples", "cherries", "oranges"].localize(:es).to_sentence # "apples, cherries y oranges"
Behind the scenes, these convenience methods are creating instances of ListFormatter. You can do the same thing if you're feeling adventurous:
f = TwitterCldr::Formatters::ListFormatter.new(:en)
f.format(["Larry", "Curly", "Moe"]) # "Larry, Curly, and Moe"
f = TwitterCldr::Formatters::ListFormatter.new(:es)
f.format(["Larry", "Curly", "Moe"]) # "Larry, Curly y Moe"
…
ruby
1.localize(:ru).plural_rule
暂无开放 Issues,或尚未同步最近议题。