stranslate

Sigbert Klinke

sigbert@hu-berlin.de

28 Januar, 2024

General

In R there are several ways to support multilingual messages:

You can access translation services that usually require a paid account, such as

There are also key-based approaches such as the translated library, which is based on JSON files. The stranslate package also uses a key-based approach, but is based on plain text files (as a lazy guy, I don’t want to follow the JSON typing rules ;).

Using stranslate

A first example

The first step is to load one or more files with translations

library("stranslate")
file <- system.file("messages", "messages.txt", package="stranslate")
loadMsg(file) # load the translation(s)

and to show what has been loaded

listMsg()     # show all loaded keys and domains
#> 
#>  Current domain  : domain
#>  Current language: lang -> en
#>  
#>  Domain: d
#>  Language: l
#>       COPYRIGHT, LANGUAGE, DOMAIN, CURRENT_LANGUAGE, CURRENT_DOMAIN
#>       MISSING_KEYS, UNDEFINED_KEYS, KEY_NOT_FOUND, KEY_LENGTH, DOMAIN_UNIQUE
#>       lang, key
#>  Language: l
#>       COPYRIGHT, LANGUAGE, DOMAIN, CURRENT_LANGUAGE, CURRENT_DOMAIN
#>       MISSING_KEYS, UNDEFINED_KEYS, KEY_LENGTH, KEY_NOT_FOUND, DOMAIN_UNIQUE
#>       lang, key
#>  
#>  Domain: d
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, user, gender
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, user, gender

We can access from the default domain some messages

getMsg(ROUND=3)
#> [1] "Round your result to 3 decimal places"
getMsg(ROUND=3, .lang="de")
#> [1] "Runden Sie ihr Ergebnis auf 3 Nachkommastellen"
getMsg(ROUND=1)
#> [1] "Round your result to one decimal place"
getMsg(ROUND=1, .lang="de")
#> [1] "Runden Sie ihr Ergebnis auf eine Nachkommastelle"

Instead of ROUND you could use 'ROUND', especially if you write a package. Since English is the fallback language, an English translation must be there.

And a multi-line example:

loadMsg(system.file("messages", "Rdewiki.txt", package="stranslate")) # load the translation(s)
getMsg("Rdewiki", .lang="en")
#> [1] "R is a free programming language for statistical calculations and graphics. It\nwas newly developed in 1992 by statisticians for users with statistical tasks.\nThe syntax is based on the programming language S, with which R is largely\ncompatible, and the semantics are based on Scheme. As a standard distribution,\nR is supplied with an interpreter as a command line environment with reduced\ngraphical buttons. Thus R is currently available on the most important platforms;\nthe environment is also explicitly referred to as R by the developers. R is part\nof the GNU project. RStudio is also offered as an integrated development\nenvironment and to increase R's user-friendliness.\nTranslated with https://www.deepl.com/translator"
getMsg(Rdewiki, .lang="de")
#> [1] "R ist eine freie Programmiersprache für statistische Berechnungen und Grafiken.\nSie wurde 1992 von Statistikern für Anwender mit statistischen Aufgaben neu\nentwickelt. Die Syntax orientiert sich an der Programmiersprache S, mit der R\nweitgehend kompatibel ist, und die Semantik an Scheme. Als Standarddistribution\nwird R mit einem Interpreter als Kommandozeilenumgebung mit reduzierten\ngrafischen Schaltflächen angeboten. So ist R aktuell auf den wichtigsten\nPlattformen verfügbar; die Umgebung wird von den Entwicklern ausdrücklich\nebenfalls als R bezeichnet. R ist Teil des GNU-Projekt. Als integrierte\nEntwicklungsumgebung und um die Benutzerfreundlichkeit von R zu erhöhen, wird\naußerdem RStudio angeboten.\nQuelle: https://de.wikipedia.org/wiki/R_(Programmiersprache)\n"

A more complex example

As you could see a key can have a parameter, also additional parameters are allowed. The current example is taken from Project fluent.

getMsg(PHOTO=5, user="Anne", gender="female")
#> [1] "Anne added 5 new photos to her stream"
getMsg(PHOTO=5, user="Anne", gender="female", .lang="de")
#> [1] "Anne fügt 5 neue Fotos ihrem Stream zu"
getMsg(PHOTO=0, user="Bert", gender="male")
#> [1] "Bert added 0 new photos to his stream"
getMsg(PHOTO=1, user="Bert", gender="male", .lang="de")
#> [1] "Bert fügt ein neues Foto seinem Stream zu"

Languages

If you want to know which languages will be used then use language.

# use German spoken in South Tirol (Italy)
# but available onby standard german and german spoken in Austria
language('de_IT', c('de', 'de_AT'))
#> [1] "de" "en"

Since de_IT is not available, de is used first. If a key is not available in de, en is used. This is the reason why you need to provide an English translation. Although all languages are equal, English is particularly important in R. Most commands and functions are based on English words.

Domains

A domain separates messages in different subsets. There are two domains:

If you do not want to load messages into the default domain, use

loadMsg(file, .domain="mydomain") # load the translation(s)
listMsg()
#> 
#>  Current domain  : domain
#>  Current language: lang -> en
#>  
#>  Domain: d
#>  Language: l
#>       COPYRIGHT, LANGUAGE, DOMAIN, CURRENT_LANGUAGE, CURRENT_DOMAIN
#>       MISSING_KEYS, UNDEFINED_KEYS, KEY_NOT_FOUND, KEY_LENGTH, DOMAIN_UNIQUE
#>       lang, key
#>  Language: l
#>       COPYRIGHT, LANGUAGE, DOMAIN, CURRENT_LANGUAGE, CURRENT_DOMAIN
#>       MISSING_KEYS, UNDEFINED_KEYS, KEY_LENGTH, KEY_NOT_FOUND, DOMAIN_UNIQUE
#>       lang, key
#>  
#>  Domain: d
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, user, gender
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, user, gender
#>  
#>  Domain: d
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, Rdewiki, user, gender
#>  Language: l
#>       ROUND, PHOTO, COUNT, STREAM, Rdewiki, user, gender

If you want to use your domain as the default domain, do the following

options(stranslate.domain='mydomain')

of use the .domain='mydomain' parameter in getMsg.

Making translations

Create translations in a txt file

In the translation file is the first character in a line important:

# switch to german
< de
# start key with its default message, note that `r ROUND` is replaced by its value
ROUND  Runden Sie ihr Ergebnis auf `r ROUND` Nachkommastellen
# if ROUND==0 then use this message
?0     Runden Sie ihr Ergebnis auf eine ganze Zahl
# if ROUND==1 then use this message
?1     Runden Sie ihr Ergebnis auf eine Nachkommastelle
# otherwise use the default message

ATTENTION: All comparison are character comparisons. If in doubt, make sure you convert your parameters yourself, e.g. getMsg(ROUND=as.character(3)).

As you can seem we use the Rmarkdown inline notation for R and internally is knitr::knit is used. This allows calculations with the parameters.

ATTENTION: Neither R code chunks nor other engines than R are supported.

Other parameters given to getMsg, e.g. getMsg(ROUND=3, user='Anne') can be used in a message, e.g.

ROUND  `r user` runde dein Ergebnis auf `r ROUND` Nachkommastellen

You can also call another key in a message with a specific value, e.g. 

PHOTO   `r user` added `r COUNT(PHOTO)` to `r STREAM(gender)` stream
COUNT   `r PHOTO` new photos
?1      a new photo
STREAM  their
?male   his
?female her

Create translations in R

setLang('en', "R")   # choose language and another domain
setMsg('ROUND'='Round your result to `r ROUND` decimal places',
       '0'='Round your result to an integer',
       '1'='Round your result to one decimal place')
setMsg(PHOTO='`r user` added `r COUNT(PHOTO)` to `r STREAM(gender)` stream')
setMsg(COUNT='`r PHOTO` new photos', '1'='a new photo')
setMsg(STREAM='their', 'male'='his', 'female'='her')
#
setLang('de', 'R')
setMsg(ROUND='Runden Sie ihr Ergebnis auf `r ROUND` Nachkommastellen',
       '0'='Runden Sie ihr Ergebnis auf eine ganze Zahl',
       '1'='Runden Sie ihr Ergebnis auf eine Nachkommastelle')
setMsg(PHOTO='`r user` fügt `r COUNT(PHOTO)` `r STREAM(gender)` Stream zu')
setMsg(COUNT='`r PHOTO` neue Fotos', '1'= 'ein neues Foto')
setMsg(STREAM='seinem', 'female'='ihrem')
#
getMsg(ROUND=3, .domain="R")
#> [1] "Round your result to 3 decimal places"

Translation files in stranslate

messages.txt

< de
ROUND  Runden Sie ihr Ergebnis auf `r ROUND` Nachkommastellen
?0     Runden Sie ihr Ergebnis auf eine ganze Zahl
?1     Runden Sie ihr Ergebnis auf eine Nachkommastelle

PHOTO   `r user` fügt `r COUNT(PHOTO)` `r STREAM(gender)` Stream zu
COUNT   `r COUNT` neue Fotos
?1      ein neues Foto
STREAM  seinem
?female ihrem

< en
ROUND   Round your result to `r ROUND` decimal places
?0      Round your result to an integer
?1      Round your result to one decimal place

PHOTO   `r user` added `r COUNT(PHOTO)` to `r STREAM(gender)` stream
COUNT   `r COUNT` new photos
?1      a new photo
STREAM  their
?male   his
?female her

Rdewiki.txt

< de
Rdewiki R ist eine freie Programmiersprache für statistische Berechnungen und Grafiken. 
        Sie wurde 1992 von Statistikern für Anwender mit statistischen Aufgaben neu 
        entwickelt. Die Syntax orientiert sich an der Programmiersprache S, mit der R 
        weitgehend kompatibel ist, und die Semantik an Scheme. Als Standarddistribution
        wird R mit einem Interpreter als Kommandozeilenumgebung mit reduzierten 
        grafischen Schaltflächen angeboten. So ist R aktuell auf den wichtigsten
        Plattformen verfügbar; die Umgebung wird von den Entwicklern ausdrücklich 
        ebenfalls als R bezeichnet. R ist Teil des GNU-Projekt. Als integrierte 
        Entwicklungsumgebung und um die Benutzerfreundlichkeit von R zu erhöhen, wird 
        außerdem RStudio angeboten.
        Quelle: https://de.wikipedia.org/wiki/R_(Programmiersprache)
  
< en
Rdewiki R is a free programming language for statistical calculations and graphics. It 
        was newly developed in 1992 by statisticians for users with statistical tasks. 
        The syntax is based on the programming language S, with which R is largely 
        compatible, and the semantics are based on Scheme. As a standard distribution,
        R is supplied with an interpreter as a command line environment with reduced 
        graphical buttons. Thus R is currently available on the most important platforms; 
        the environment is also explicitly referred to as R by the developers. R is part
        of the GNU project. RStudio is also offered as an integrated development 
        environment and to increase R's user-friendliness.
        Translated with https://www.deepl.com/translator

stranslate.txt

< de
COPYRIGHT        (C) 2023+ S. Klinke, Humboldt-Universität zu Berlin
LANGUAGE         Sprache: `r LANGUAGE`
DOMAIN           Domäne : `r DOMAIN`
CURRENT_LANGUAGE Aktuelle Sprache: `r CURRENT_LANGUAGE`
CURRENT_DOMAIN   Aktuelle Domäne : `r CURRENT_DOMAIN`
MISSING_KEYS     Für die Sprache '`r lang`' fehlt der/die Schlüssel: `r MISSING_KEYS`
UNDEFINED_KEYS   Undefinierte Schlüssel: `r UNDEFINED_KEYS`
KEY_LENGTH       'key' muss die Länge 1 haben, vielleicht funktioniert '"key"'
KEY_NOT_FOUND    Schlüssel '`r key`' nicht in '`r lang`' gefunden, vielleicht meinten Sie:
DOMAIN_UNIQUE    Es muss eine eindeutige Domäne angegeben werden

< en
COPYRIGHT        (C) 2023+ S. Klinke, Humboldt-Universität zu Berlin
LANGUAGE         Language: `r LANGUAGE`
DOMAIN           Domain: `r DOMAIN`
CURRENT_LANGUAGE Current language: `r CURRENT_LANGUAGE`
CURRENT_DOMAIN   Current domain  : `r CURRENT_DOMAIN`
MISSING_KEYS     Missing for language '`r lang`' the key(s): `r MISSING_KEYS`
UNDEFINED_KEYS   Undefined key(s): `r UNDEFINED_KEYS`
KEY_NOT_FOUND    Key '`r key`' not found in '`r lang`', maybe you meant:
KEY_LENGTH       'key' must have length 1, maybe '"key"' works
DOMAIN_UNIQUE    A unique domain must be specified

messages.R

setLang('en') # adds to domain 'default'
setMsg('ROUND'='Round your result to `r ROUND` decimal places',
       '0'='Round your result to an integer',
       '1'='Round your result to one decimal place')
setMsg(PHOTO='`r user` added `r COUNT(PHOTO)` to `r STREAM(gender)` stream')
setMsg(COUNT='`r PHOTO` new photos',
       '1'='a new photo')
setMsg(STREAM='their',
       'male'='his',
       'female'='her')
#
setLang('de') # adds to domain 'default'
setMsg(ROUND='Runden Sie ihr Ergebnis auf `r ROUND` Nachkommastellen',
       '0'='Runden Sie ihr Ergebnis auf eine ganze Zahl',
       '1'='Runden Sie ihr Ergebnis auf eine Nachkommastelle')
setMsg(PHOTO='`r user` fügt `r COUNT(PHOTO)` `r STREAM(gender)` Stream zu')
setMsg(COUNT='`r PHOTO` neue Fotos',
       '1'= 'ein neues Foto')
setMsg(STREAM='seinem',
       'female'='ihrem')