All Projects → crimson-knight → i18n.cr

crimson-knight / i18n.cr

Licence: MIT license
Internationalization API ( i18n ) for Crystal!

Programming Languages

crystal
512 projects

Projects that are alternatives of or similar to i18n.cr

Easy localization
Easy and Fast internationalizing your Flutter Apps
Stars: ✭ 407 (+1030.56%)
Mutual labels:  i18n, translation, internationalization, localization
fluent-vue
Internationalization plugin for Vue.js
Stars: ✭ 137 (+280.56%)
Mutual labels:  i18n, translation, internationalization, localization
Fluent.js
JavaScript implementation of Project Fluent
Stars: ✭ 622 (+1627.78%)
Mutual labels:  i18n, translation, internationalization, localization
Eo Locale
🌏Internationalize js apps 👔Elegant lightweight library based on Internationalization API
Stars: ✭ 290 (+705.56%)
Mutual labels:  i18n, translation, internationalization, localization
Formatjs
The monorepo home to all of the FormatJS related libraries, most notably react-intl.
Stars: ✭ 12,869 (+35647.22%)
Mutual labels:  i18n, translation, internationalization, localization
Js Lingui
🌍📖 A readable, automated, and optimized (5 kb) internationalization for JavaScript
Stars: ✭ 3,249 (+8925%)
Mutual labels:  i18n, translation, internationalization, localization
React Intl Hooks
React hooks for internationalization without the hassle ⚛️🌍
Stars: ✭ 64 (+77.78%)
Mutual labels:  i18n, translation, internationalization, localization
plate
Internationalization library for Python
Stars: ✭ 31 (-13.89%)
Mutual labels:  i18n, translation, internationalization, localization
Dom I18n
Provides a very basic HTML multilingual support using JavaScript
Stars: ✭ 125 (+247.22%)
Mutual labels:  i18n, translation, internationalization, localization
Phabricator zh hans
Phabricator zh-Hans Translation & Tools.
Stars: ✭ 113 (+213.89%)
Mutual labels:  i18n, translation, internationalization, localization
Mojito
An automation platform that enables continuous localization.
Stars: ✭ 256 (+611.11%)
Mutual labels:  i18n, translation, internationalization, localization
React Translated
A dead simple way to add complex translations (i18n) in a React (DOM/Native) project 🌎🌍🌏
Stars: ✭ 176 (+388.89%)
Mutual labels:  i18n, translation, internationalization, localization
Traduora
Ever® Traduora - Open-Source Translation Management Platform
Stars: ✭ 1,580 (+4288.89%)
Mutual labels:  i18n, translation, internationalization, localization
React Localize Redux
Dead simple localization for your React components
Stars: ✭ 384 (+966.67%)
Mutual labels:  i18n, translation, internationalization, localization
labels
Bolt Labels extension - Translatable labels for Bolt
Stars: ✭ 18 (-50%)
Mutual labels:  i18n, translation, internationalization, localization
Frenchkiss.js
The blazing fast lightweight internationalization (i18n) module for javascript
Stars: ✭ 776 (+2055.56%)
Mutual labels:  i18n, translation, internationalization, localization
inlang
Open Source Localization Solution for Software.
Stars: ✭ 160 (+344.44%)
Mutual labels:  i18n, translation, internationalization, localization
rosetta
A blazing fast internationalization (i18n) library for Crystal with compile-time key lookup.
Stars: ✭ 23 (-36.11%)
Mutual labels:  i18n, translation, internationalization, localization
Pseudo Localization
Dynamic pseudo-localization in the browser and nodejs
Stars: ✭ 109 (+202.78%)
Mutual labels:  i18n, translation, internationalization, localization
Node Gettext
A JavaScript implementation of gettext, a localization framework.
Stars: ✭ 175 (+386.11%)
Mutual labels:  i18n, translation, internationalization, localization

i18n - Internationalization Library for Crystal

Build Status license tag

Installation

Add this to your application's shard.yml:

dependencies:
  i18n:
    github: crimson-knight/i18n.cr

Usage

I18n.translate(
  "some.dot.separated.path",  # key : String
  {attr_to_interpolate: "a"}, # options : Hash | NamedTuple? = nil
  "pt",                       # force_locale : String = nil
  2,                          # count : Numeric? = nil
  "default translation",      # default : String? = nil
  nil                         # iter : Int? = nil
)

I18n.localize(
  Time.utc_now, # object : _
  "pt",         # force_locale : String = I18n.config.locale
  :time,        # scope : Symbol? = :number
  "long"        # format : String? = nil
)

Arguments interpolation

Translation may include argument interpolation. For doing this use regular crystal named interpolation placeholder and pass hash or named tuple as a options argument:

message:
  new: "New message: %{text}"
# New message: hello
I18n.translate("message.new", {text: "hello"})
I18n.translate("message.new", {:text => "hello"})
I18n.translate("message.new", {"text" => "hello"})

Also any extra key-value pair will be ignored and missing one will not cause any exception:

I18n.translate("message.new", {message: "hello"}) # New message: %{text}

Configuration

require "i18n"

I18n.load_path += ["spec/locales"]
I18n.init # This will load locales from all specified locations

I18n.default_locale = "pt" # default can be set after loading translations

There is a handler for Kemalyst that bring I18n configuration.

Available backends

I18n::Backend::Yaml

A simple backend that reads translations from YAML files and stores them in an in-memory hash. Also supports JSON files and translations embedding.

I18n::Backend::Chain

Backend that chains multiple other backends and checks each of them when a translation needs to be looked up. This is useful when you want to use standard translations with a custom backend to store custom application translations in a database or other backends.

To use the Chain backend instantiate it and set it to the I18n module. You can add chained backends through the initializer:

require "i18n/backend/chain"

other_backend = I18n::Backend::Yaml.new # your other backend
I18n.backend.load("config/locales/en.yml")
other_backend.load("config/locales/pl.yml")
I18n.backend = I18n::Backend::Chain.new([I18n.backend, other_backend2] of I18n::Backend::Base)

# or if it is ok to pass files to each backend

I18n.backend = I18n::Backend::Chain.new([I18n.backend, I18n::Backend::Yaml.new] of I18n::Backend::Base)
I18n.load_path = ["config/locales/{en,pl}.yml"]
I18n.load

I18n::Backend::Fallback

I18n locale fallbacks are useful when you want your application to use translations from other locales when translations for the current locale are missing. E.g. you might want to use en translations when translations in your applications main locale de are missing.

To enable locale fallbacks you can instantiate fallback backend giving it your backend as an argument:

require "i18n/backend/fallback"

I18n.load_path = ["config/locales"]
I18n.init
I18n.backend = I18n::Backend::Fallback.new(I18n.backend, {"en-US" => "en", "en-UK" => "en"})

Note on YAML Backend

Putting translations for all parts of your application in one file per locale could be hard to manage. You can store these files in a hierarchy which makes sense to you.

For example, your config/locales directory could look like this:

locales
|--defaults
|----en.yml
|----pt.yml
|--models
|----en.yml
|----pt.yml
|--views
|----users
|------en.yml
|------pt.yml

This way you can separate model related translations from the view ones. To require all described subfolders at once use ** - I18n.load_path += ["locals/**/"]

Any .json file located in the file hierarchy specified for load_path is also read and parsed.

Date/Time Formats

To localize the time (or date) format you should pass Time object to the I18n.localize. To pick a specific format path format argument:

I18n.localize(Time.local, scope: :date, format: :long)

By default Time will be localized with :time scope.

To specify formats and all need localization information (like day or month names) fill your file in following way:

NOTE: According to ISO 8601, Monday is the first day of the week

__formats__:
  date:
    formats:
      default: '%Y-%m-%d' # is used by default
      long: '%A, %d de %B %Y'
    month_names: # long month names
      - Janeiro
      - Fevereiro
      - Março
      - Abril
      - Maio
      - Junho
      - Julho
      - Agosto
      - Setembro
      - Outubro
      - Novembro
      - Dezembro
    abbr_month_names: # month abbreviations
      - Jan
      - Fev
      # ...
    day_names: # fool day names
      - Segunda
      # ...
    abbr_day_names: # short day names
      - Seg
      # ...

Format accepts any crystal Time::Format directives. Also following directives will be automatically localized:

Directive Description Key
%a short day name date.abbr_day_names
%A day name date.day_names
%b short month name date.abbr_month_names
%B month name date.month_names
%p am-pm (lowercase) time.am/time.pm
%P AM-PM (uppercase) time.am/time.pm

Pluralization

In many languages — including English — there are only two forms, a singular and a plural, for a given string, e.g. "1 message" and "2 messages". Other languages (Arabic, Japanese, Russian and many more) have different grammars that have additional or fewer plural forms.

The count interpolation variable has a special role in that it both is interpolated to the translation and used to pick a pluralization from the translations according to the pluralization rules defined by CLDR:

message:
  one: "%{count} message"
  other: "%{count} messages"
I18n.translate("message", count: 1) # 1 message
I18n.translate("message", count: 2) # 2 messages
I18n.translate("message", count: 0) # 0 messages

count should be passed as argument - not inside of options. Otherwise regular translation lookup will be applied.

I18n defines default CLDR rules for many locales (see src/i18n/config/plural_rules), however they can be overwritten:

I18n.plural_rules["ru"] = ->(n : Int32) {
  if n == 0
    :zero
  elsif ((n % 10) == 1) && ((n % 100 != 11))
    # 1, 21, 31, 41, 51, 61...
    :one
  elsif ([2, 3, 4].includes?(n % 10) && ![12, 13, 14].includes?(n % 100))
    # 2-4, 22-24, 32-34...
    :few
  elsif ((n % 10) == 0 || ![5, 6, 7, 8, 9].includes?(n % 10) || ![11, 12, 13, 14].includes?(n % 100))
    # 0, 5-20, 25-30, 35-40...
    :many
  else
    :other
  end
}
kid:
  zero: 'нет детей'
  one: '%{count} ребенок'
  few: '%{count} ребенка'
  many: '%{count} детей'
  other: '%{count} детей'
I18n.locale = "ru"

I18n.translate("kid", count: 0) # нет детей
I18n.translate("kid", count: 1) # 1 ребенок
I18n.translate("kid", count: 2) # 2 ребенка
I18n.translate("kid", count: 6) # 6 детей

Iteration

To store several alternative objects under one localization key they could be just listed in the file and later retrieved using iter argument:

NOTE : The first index is 0

__formats__:
  date:
    day_names: [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
I18n.translate("__formats__.date.day_names", iter: 2)  # >>> "Wednesday"

Embedding translations inside your binary

Changes from 0.4.0 to 0.4.1

  • Supported Crystal versions of >= 0.35
  • add Backend::Yaml#exists? to check whether given translation key exists
  • add I18n.exists?
  • add docs to I18n module public methods (most of wording was taken from the ruby I18n repo)
  • Fixed the iter argument in translate to properly return the correct index

Example

  # Array we are looking into ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
  I18n.translate("__formats__.date.day_names", iter: 2) # Returns "Wednesday"

Breaking changes from 0.3 to 0.4

  • Pluralization rules are now fully suites CLDR convention. Specifically en pluralization no more returns zero

Breaking changes from 0.2 to 0.3

  • The first day of the week is now Monday according to ISO 8601.
  • The nil value in month_names and abbr_month_names was removed.

You can embed translations inside your binary by using the following macro call:

I18n::Backend::Yaml.embed(["some/locale/directory", "some/other/locale/directory"])

Contributing

  1. Fork it ( https://github.com/crimson-knight/i18n/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Inspiration taken from:

Special thank you to [TechMagister] for being the original owner and creator of this shard.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].