src/ni18n

  Source   Edit

ni18n is Super Fast Nim Macros For Internationalization and Localization.

It generates functions for each translation name at compile time. So, there's no runtime translation lookup like HashMap.

Example:

import src/ni18n

type
    Locale = enum
        English
        Chinese

i18nInit Locale, true:
    hello:
        English = "Hello, $name!"
        Chinese = "你好, $name!"
    ihaveCat:
        English = "I've cats"
        Chinese = "我有猫"
        withCount:
            English = proc(count: int): string =
                case count
                of 0: "I don't have a cat"
                of 1: "I have one cat"
                else: "I have " & $count & " cats"
            Chinese = proc(count: int): string =
                proc translateCount(count: int): string =
                    case count
                    of 2: "二"
                    of 3: "三"
                    of 4: "四"
                    of 5: "五"
                    else: $count

                return case count
                    of 0: "我没有猫"
                    of 1: "我有一只猫"
                    else: "我有" & translateCount(count) & "只猫"

# prints "你好, 黄小姐!". This function behave the same as `strutils.format`
echo hello(Chinese, "name", "黄小姐")

# prints 我有猫
echo ihaveCat(Chinese)

# prints 我有五只猫
echo ihaveCat_withCount(Chinese, 5)

# or like this ( because Nim compiler is smart! )
echo ihaveCatWithCount(Chinese, 5)

Notes For `ni18n` DSL

DSL has top-level translation definitions and sub-translation definitions. Each translation definition can have multiple sub-translation definitions.

root                 = seq[topLevelTranslation] ;
topLevelTranslation  = nameIdent ":" seq[translationPair] ;
translationPair      = localeIdent "=" translation
                     | nameIdent ":" seq[translationPair] ;
translation          = nnkStrLit | nnkLambda ;

  • Translation must exists for all possible locales.
  • nnkLambda must have the same signature for all locales.

Behind the Scene

Imagine u write this code:

type
    Locale = enum
        English
        Chinese

i18nInit Locale, true:
    hello:
        English = "Hello, $name!"
        Chinese = "你好, $name!"

Magic macro will convert that code into this:

type
    Locale = enum
        English
        Chinese

proc hello_English(args: varargs[string, `$`]): string =
    format("Hello, $name!", args)

proc hello_Chinese(args: varargs[string, `$`]): string =
    format("你好, $name!", args)

proc hello*(locale: Locale, args: varargs[string, `$`]): string =
    case locale
    of English: hello_English(args)
    of Chinese: hello_Chinese(args)

So, we have just locale runtime check, but since that's enum, we're still going fast!


See also

Macros

macro i18nInit(enumT: typedesc; shouldExportLookup: static bool;
               translationPairs: untyped): untyped
compile translations DSL into locale specific procedures and lookup procedures
  • enumT is the enum that contains all available locales
  • shouldExportLookup is a boolean that indicates whether to export lookup functions
  • translationPairs is a list of translation pairs

In most cases, shouldExportLookup should be set to true because u want to write translations in a separate file and import generated lookup functions from other modules.

  Source   Edit