i18n
Version, currently 0.3.16 versions
github.com/crimson-knight/i18n.cr
Internationalization API ( i18n ) for Crystal!
41 stars
0 dependents
License: MIT
Nothing has been indexed for 0.3.1 yet. The tag is recorded, its shard.yml has not been read, so the manifest and dependency list below are empty because they are unknown rather than because they are absent.
Installation
# Add this to your shard.yml
dependencies:
i18n:
github: crimson-knight/i18n.cr
version: ~> 0.3.1Then run:
shards installshard.yml
No shard.yml has been indexed for 0.3.1. You can read it on the repository.
Dependencies
Unknown: the shard.yml for this version has not been read yet.
Documentation
Generated from the source of the current release. The first visit to a release that has never been documented starts its build.
README
This README is the one indexed from the repository at its latest ref, not from the tag for this version.
# i18n

Internationalization API
## 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
```crystal
# 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](http://cldr.unicode.org/index/cldr-spec/plural-rules). 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.
## Installation
Add this to your application's `shard.yml`:
```yaml
dependencies:
i18n:
github: crimson-knight/i18n.cr
```
## Usage
``` crystal
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:
```yaml
message:
new: "New message: %{text}"
```
```crystal
# 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:
```crystal
I18n.translate("message.new", {message: "hello"}) # New message: %{text}
```
### Configuration
```crystal
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](https://github.com/TechMagister/kemalyst-i18n) for Kemalyst that bring I18n configuration.
### 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:
```console
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/**/"]`
#### 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:
```crystal
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
```yaml
__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:
```yaml
message:
one: "%{count} message"
other: "%{count} messages"
```
```crystal
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](http://cldr.unicode.org/index/cldr-spec/plural-rules) for many locales (see `src/i18n/config/plural_rules`), however they can be overwritten:
```crystal
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
}
```
```yaml
kid:
zero: 'нет детей'
one: '%{count} ребенок'
few: '%{count} ребенка'
many: '%{count} детей'
other: '%{count} детей'
```
```crystal
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`
```yaml
__formats__:
date:
day_names: [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
```
```crystal
I18n.translate("__formats__.date.day_names", iter: 2) # >>> "Wednesday"
```
### Embedding translations inside your binary
You can embed translations inside your binary by using the following macro call:
```crystal
I18n::Backend::Yaml.embed(["some/locale/directory", "some/other/locale/directory"])
```
## Development
TODO :
- [ ] Add more backends ( Database, json based, ruby based ( why not ? ))
- [ ] others ( there is always something to add ... or remove )
## 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
- [[crimson-knight]](https://github.com/crimson-knight) Seth Tucker (New owner as of July 2021)
- [[imdrasil]](https://github.com/imdrasil) Roman Kalnytskyi
Inspiration taken from:
- https://github.com/whity/crystal-i18n
- https://github.com/mattetti/i18n
Special thank you to [[TechMagister]](https://github.com/Techmagister) for being the original owner and creator of this shard.
Links
This release
- Version
0.3.1- Tagged
- Aug 5, 2026
- Commit
ed60fa3268a8- Indexed
- not yet
Dependents
No indexed shard depends on this one yet.
Repository
github.com/crimson-knight/i18n.cr
Metadata
- Created
- Aug 12, 2026
- Updated
- Aug 12, 2026
- Synced
- Aug 12, 2026
- Versions
- 6