# Localization

Crystal I18n provides basic localization features for datetimes and numbers. Localization can be achieved through the use of the #localize method (or its shorter version #l).

# Localizing dates and datetimes

Localizing dates and datetimes requires a specific structure to be defined in translation files for each of the available locales. Here is an example of the expected structure for the en locale:

en:
  i18n:
    date:
      abbr_day_names: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
      abbr_month_names: [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
      day_names: [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
      month_names: [January, February, March, April, May, June,
                    July, August, September, October, November, December]
      formats:
        default: "%Y-%m-%d"
        long: "%B %d, %Y"
        short: "%b %d"
    time:
      am: am
      formats:
        default: "%a, %d %b %Y %H:%M:%S %z"
        long: "%B %d, %Y %H:%M"
        short: "%d %b %H:%M"
      pm: pm

The above structure defines basic translations for the relevant directives that can be outputted when localizing dates and datetimes. It also defines a few formats under the i18n.date.formats and i18n.time.formats scopes: among these formats, only the default one is really mandatory since this is the one that is used by default if no other format is explicitly provided to the #localize method.

The directives used in the above formats are all defined in the Time::Format (opens new window) struct. As such, custom formats can be created from any of the directives provided by Time::Format (opens new window), for example %Y-%m-%d %H:%M:%S %z is a valid format. Some of these directives (eg. month names) are translated too and thus additional translation keys have to be defined for those too ; here is a list of the translation keys that need to be defined for these special time format directives:

Directive Translation key Description
%a i18n.date.abbr_day_names Short day name (Sun, Mon, Tue, ...)
%A i18n.date.day_names Day name (Sunday, Monday, Tuesday, ...)
%b i18n.date.abbr_month_names Short month name (Jan, Feb, Mar, ...)
%B i18n.date.month_names Month name (January, February, March, ...)
%p i18n.time.am/i18n.time.pm am-pm

Given the above structure and formats definition, it is possibles to localize date and datetimes as follows:

I18n.localize(Time.local)             # outputs "Sun, 13 Dec 2020 21:11:08 -0500"
I18n.localize(Time.local, :short)     # outputs "13 Dec 21:11"
I18n.localize(Time.local.date)        # outputs "2020-12-13"
I18n.localize(Time.local.date, :long) # outputs "December 13, 2020"

# Localizing numbers

Localizing numbers requires a specific structure to be defined in translation files for each of the available locales. Here is an example of the expected structure for the en locale:

en:
  i18n:
    number:
      formats:
        default:
          delimiter: ","
          separator: "."
          decimal_places: null
          group: 3
          only_significant: false

The above structure defines a single default format for numbers: similarly to dates or datetimes this default format is mandatory since it'll be used automatically if no explicit format is provided to the #localize method, but custom formats can be defined as well.

Each number format defines how numbers should be formatted for the given locale according to 5 formatting options:

Option Default Description
delimiter "," Thousands delimiter between batches of group digits (defaults to)
separator "." Decimal separator
decimal_places null Number of visible decimal places (no value means that all significant decimal places are printed)
group 3 Number of digits composing the batches of digits used for thousands (defaults to 3)
only_significant false Whether trailing zeros should be omitted (defaults to false)

TIP

The above number formatting options are consistent with the arguments that can be used with Number#format (opens new window)

Given the above structure and formats definition, it is possibles to localize numbers as follows:

I18n.localize(123_456)              # outputs "123,456"
I18n.localize(123_456.789)          # outputs "123,456.789"
I18n.localize(123_456.789, :custom) # outputs "123,456.79"