Internationalization of Crystal programs.
HEAD Latest release released

i18n for the Crystal programming language

THIS IS THE OLD VERSION. The new version is at http://github.com/BrucePerens/internationalize, and will be checked in here when it's more stable.


  require "i18n"
  include I18n

  t "Any string." # => "translated string"

Translate a String, even an interpolated string. Check that a translation for each string, into each language, exists at compile time, and abort compilation with an error if one does not. Work-in-progress translations can indicate that a compilation check is not desired.

An interpolated string is broken up into fixed string segments, and these are translated individually.

The argument must be a literal string (including interpolated strings), not a method, expression, or variable. This is because much of the translation mechanism runs at compile-time.

When the argument -Demit-translation-strings is provided to crystal build, the compiler will emit a table of all of the strings that are provided as arguments to the t() function, possibly including duplicates. These are written to STDOUT using the Crystal::Macros#p method. This table can be edited into a translation file by the programmer, and is intended to be used by a task for generating such files with machine translation (not yet written).

Languages are referred to using IETF language tags . Two common language tags are "en-US" for English as spoken in the United States, and "en" for English not distinguishing where it is spoken.

Translations are defined in a NamedTuple called Translations, which must exist at the top level. Each translation is defined as a tuple of a language tag and an inner tuple containing translations into that language from the native language used in the program (the "coding language"). Thus, the Translations tuple looks like this:

Translations = { # Assuming the coding language tag is "en-US"
  "en" => { # English as spoken in most places other than the USA
    "the color of money" => "the colour of money",
  "es" => { # Spanish (not distinguishing Spain or Mexico)
    "the color of money" => "el color del dinero"
  "es-MX" => { # Mexican Spanish
    "the color of money" => "el color del dinero"
  "de" => { # German (not distinguishing Swiss-German, etc.)
    "the color of money" => "die Farbe des Geldes",

A constant CodingLanguage must exist at the top level, and is set to a string indicating the language used to write the native strings. So it would have the form CodingLanguage="en-US". CodingLanguage should indicate where it is spoken, thus "en-US" rather than "en". This allows, for example, a translation to correct for spelling differences between US English and the English spoken in the United Kingdom ("en-GB").

A variable or method language_tag must exist in the context where the t() function is called, which is or returns a string for the language tag of the present user. So, this would be of the form language_tag = "es" for Spanish (not distinguishing Castilian or Mexican Spanish). Note that language_tag need not be global, it may exist as a method or a local variable, as long as it is defined in all contexts where t() is called.

Work-in-progress language translations are designated by modifying their language tag with a "wip- prefix, so that the compiler does not test those tranlations for completion. For example, a work-in-progress translation into Spanish would have the tag "wip-es". To test a work-in-progress translation, language_tag must be set to the modified form. It is possible for a work-in-progress translation and a completed one to exist to the same language, for example "wip-es" and "es". This allows the same source code to work with a working-but-awkward machine tranlation while a human translator produces a better version.

NOTE: Complications of Translation

At some point you will be askng translators to translate your strings into different languages. You will probably start with a machine translation, but these can not be expected to be correct, especially where interpolated strings are concerned. There is not an exact one-to-one mapping of words in two languages to the same meaning. Nor can you expect the order of words in a sentence to remain the same, since grammars vary widely between languages. Thus, a translation of an interpolated string can be awkward. The original writer's assumptions about what belongs before and after any variables or expressions in the string may not carry over to the grammar of the translated language.

To delve briefly into just one of the many differences between languages that complicate translation: Many languages like English have no grammatical gender for nouns, while others gender nouns male and female, male female and neuter, or common and neuter. Some languages group nouns into animate and inanimate forms, and some include noun class modifiers which indicate several different forms of a noun. Such language differences can require your translator to make assumptions about what you have written. The default gender is usually male, which can lead to your translation being masculinized in ways you did not expect.

  github: BrucePerens/i18n
License Apache 2.0
Crystal 0.27


Dependencies 0

Development Dependencies 0

Dependents 1

Last synced .
search fire star recently