lens

A multiformat internationalization (i18n) shard for Crystal. Supports Gettext, Ruby YAML, etc gettext i18n l18n internationalization localization l10n translation locale language
0.1.0 Latest release released
syeopite/lens
8 1 3
syeopite

lens

A multiformat internationalization (i18n) shard for Crystal.

There is no doubt that the crystal community lacks many essential features that most modern day languages have; one of which is internationalization. Lens is an attempt to fix that.

Getting started

Lens supports numerous different formats:

  • GNU Gettext (Gettext::POBackend, Gettext::MOBackend)
    • You can use both .po and .mo
  • Crystal-i18n (CrystalI18n::I18n)
    • Stored under .yml
  • More coming soon

To get started, you should select one that fits your needs the best. See here for information regarding them.

Each backend can then be initialized with the locale directory

backend = Gettext::MOBackend.new("locales")

Each backend also supports nested directories and multiple files of the same language.

GNU Gettext

The GNU project's implementation of Gettext

backend = Gettext::MOBackend.new("locales")
catalogue_hash = backend.create() # => LanguageCode|| Filename => Catalogue 
catalogue = catalogue_hash["en_US"]

For detailed information regarding usage please refer to the actual API documentation. A brief overview of the functionality is present below.

Basic usage

Messages are fetched with the gettext method. If it doesn't exist then the given ID would be returned.

catalogue.gettext("A message")     # => "Translated message"
catalogue.gettext("I don't exist") # => "I don't exist"

Pluralization

Pluralization is done through the ngettext method. The given number is parsed through the C expression from the Plural-Forms header to know which plural-form to use.

catalogue.ngettext("I have %d apple", "I have %d apples", 0) # => "Translated I have %d apple"
catalogue.ngettext("I have %d apple", "I have %d apples", 1) # => "Translated I have %d apples"

Context

Key can be constrained by a specific context and is accessed through the pgettext method.

catalogue.pgettext("CopyPasteMenu", "copy")          # => "Translated copy"
catalogue.pgettext("CopyPasteMenu", "I don't exist") # => "I don't exist"

Context with pluralization

Context-constrained messages can also have plural-forms and is accessed through the npgettext method

catalogue.npgettext("CopyPasteMenu", "Export %d file", "Export %d files", 0) # => "Translated message with plural-form 1"
catalogue.npgettext("CopyPasteMenu", "Export %d file", "Export %d files", 1) # => "Translated message with plural-form 0"

Crystal-i18n

Is a format based on ruby-yml similar to what many others in the crystal community has implemented.

# The backend is the catalogue in the case of crystal-i18n
catalogue = CrystalI18n::I18n.new("locales")

Each file should be named like language-code.yml

For detailed information regarding usage please refer to the actual API documentation. A brief overview of the functionality is present below.

Basic usage

catalogue.translate("en", "translation") # => "Translated Message"

Nested keys can be accessed by separating routes with .

catalogue.translate("en", "nested_key.forth.forth-third.forth-third-fifth.4344")

Pluralization

catalogue.translate("en", "possessions.fruits.apples", 50) # => "I have 50 apples"
catalogue.translate("en", "possessions.fruits.apples", 1)  # => "I have 1 apple"

Plural-rules follows CLDR and is pre-defined in lens for many languages. If your language isn't included in lens you many define (or even overwrite) a new plural-rule through the CrystalI18n.define_rule method

  CrystalI18n.define_rule("ar", ->(n : Int32 | Int64 | Float64) {
  case
  when n == 0             then "zero"
  when n == 1             then "one"
  when n == 2             then "two"
  when 3..10 === n % 100  then "few"
  when 11..99 === n % 100 then "many"
  else                         "other"
  end
})

Interpolation

Interpolation is done through keyword arguments in the #translate method

# message is 'Hello there, my name is %{name} and I'm a %{profession}`.
result = catalogue.translate("en", "introduction.messages", name: "Steve", profession: "programmer")
result # => "Hello there, my name is Steve and I'm a programmer"

Iteration

If the value at the given path (key) turns out to be an array then you can pass in the iter argument to select a specific value at the given index

catalogue.translate("en", "items.foods", iter: 2) # => "Hamburger"

API documentation

Here

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      lens:
        github: syeopite/lens
    
  2. Run shards install

Contributing

  1. Fork it (https://github.com/syeopite/lens/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

Inspirations

lens:
  github: syeopite/lens
  version: ~> 0.1.0
License MIT
Crystal >= 1.0, < 2.0

Authors

Dependencies 0

Development Dependencies 0

Dependents 0

Last synced .
search fire star recently