Skip to content

iffy/nim-intl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The intl Nim package make it easy to do internationalization (i18n) and localization (l10n) in Nim programs.

tests

This is alpha-quality. Please file issues for any bugs you encounter.

Features

  • Compact message format
  • Automatic message extraction during compilation
  • Message format indicates what's been translated
  • Really fast message lookup
  • Flexibility beyond pluralizing
  • Multiple message repositories (e.g. your program has one list of messages, and a library you import has its own)
  • Extracted messages can automatically update message files during compilation (if you want)
  • Select a single locale at compile time and avoid all runtime message lookups.
  • Warn about duplicate message keys for non-matching values
  • Don't require labels for proc messages. See nim-lang/Nim#15004

Quickstart

Intall intl:

nimble install https://github.com/iffy/nim-intl.git

Run the following to generate some boilerplate in the ./trans directory:

intl init

Follow the instructions emitted by intl init to incorporate the newly generated catalog into your code. For instance, add locales for English and Chinese:

intl add en
intl add zh

Create a Nim file (or add some of the following to an existing one):

# main.nim
import ./trans/all
if paramCount() > 0:
  setLocale(paramStr(1))
echo tr"Hello, World!"
intlPostlude(currentSourcePath(), "trans")

Compile, which will automatically extract messages for translation in locale-specific files within ./trans/:

nim c main.nim

Edit trans/zh.nim to perform translation.

# trans/zh.nim - Before translating
import ./base
messages "zh":
  todo 71994, "s_rhellowor71994", r"Hello, World!"
# trans/zh.nim - After translating
import ./base
messages "zh":
  done 71994, "s_rhellowor71994", r"你好,世界!"

Recompile:

nim c main.nim

Run the localized program!

$ ./main en
Hello, World!
$ ./main zh
你好,世界!

More examples

This program prints out one translateable message:

import intl
intlCatalog "myprogram"

# `tr` marks strings for translation
echo tr"Hello, World!"

# Emit extracted messages during compilation
intlPostlude()

Because of the intlPostlude() call, compilation generates the extracted messages, which you can paste back into your code:

## ==== intl postlude ====
baseMessages:
  msg "s_rhellowor71994", r"Hello, World!"
## ==== end intl postlude ====

Let's put the baseMessages: block in as well as the start of a locale for Spanish using messages "localename"::

import intl
intlCatalog "myprogram"

baseMessages:
  msg "s_rhellowor71994", r"Hello, World!"

messages "es":
  discard

echo tr"Hello, World!"
intlPostlude()

Compile this file, and it will provide a fleshed-out set of Spanish messages, ready to be translated:

## ==== intl postlude ====
baseMessages:
  msg "s_rhellowor71994", r"Hello, World!"

messages "es":
  todo 71994, "s_rhellowor71994", r"Hello, World!"
## ==== end intl postlude ====

Changing locale

Use setLocale() to change the locale. The following will print ¡Hola!:

import intl
intlCatalog "myprogram"

baseMessages:
  msg "s_rhellowor71994", r"Hello, World!"

messages "es":
  done 71994, "s_rhellowor71994", r"¡Hola!"

setLocale("es")
echo tr"Hello, World!"
intlPostlude()

Message keys

You may specify the key used to identify each message, rather than the autogenerated one by calling tr with 2 arguments like this:

echo tr("greeting", "Hello, World!")

This produces:

baseMessages:
  msg "greeting", "Hello, World!"

messages "es":
  todo 32096, "greeting", "Hello, World!"

Pluralization

intl let's you use a Nim proc to do whatever is needed for pluralizing. Translators will translate Nim functions. Consider the following:

import intl
intlCatalog "myprogram"

echo "You have " & tr("num-animals", proc(cats:int, dogs:int):string =
  result = $cats & " "
  if cats == 1:
    result.add("cat")
  else:
    result.add("cats")
  result.add " and " & $dogs & " "
  if dogs == 1:
    result.add("dog")
  else:
    result.add("dogs")
  result.add(".")
)(1, 6)

intlPostlude()

Compiling and running produces:

## ==== intl postlude ====
baseMessages:
  msg "num-animals", proc (cats: int; dogs: int): string =
    result = "You have " & $cats & " "
    if cats == 1:
      result.add("cat")
    else:
      result.add("cats")
    result.add " and " & $dogs & " "
    if dogs == 1:
      result.add("dog")
    else:
      result.add("dogs")
    result.add(".")
## ==== end intl postlude ====
You have 1 cat and 6 dogs.

Warning: Because procs can be used, remember to audit translations from other sources.

Tracking

Messages within each messages "locale": block have the following format:

  <status> <hash>, "<key>", <value>

<status> is one of the following:

  • todo - This message needs to be translated. When done translating, the translator should change this to done
  • done - This message is translated. Translators change the status to done to indicate that the translation has been complete.
  • redo - This message possibly needs to be re-translated. The compiler marks messages as redo when the underlying message has changed.
  • gone - This message is no longer present in the source code.

<hash> is an opaque hash computed from the message value. It's used to determine if a messages should be marked as redo. Users should leave this alone.

<key> is the auto-generated or user-provided unique key for this message. Users should leave this alone.

<value> is the localized value for the message. Users should change this.

Automatic catalog updating

If you want intl to automatically update message catalogs, call the postlude like this:

import intl
intlCatalog "mycatalog"
intlPostlude(currentSourcePath(), "trans")

This will cause files to be written in ./trans. After the first time running this, change your main Nim file to this:

import ./trans/all
intlPostlude(currentSourcePath(), "trans")

Add locales by creating empty Nim files named ./trans/XX.nim where XX is the locale name. Recompile and they will be populated with your messages.

Design

Speed

All message lookups are simply attribute access on the currently-selected locale's messages. This is probably fast (though I haven't measured anything). Consider this echo statement:

echo tr"Hello, World!"

In the case where the message is in baseMessages:, it expands to:

echo [selectedMessages_myprogram.s_rhellowor71994]

And if the message hasn't yet been added to baseMessages:, it reverts to the literal value:

echo ["Hello, World!"]

About

Nim library for i18n and l10n

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages