Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

4. Using gettext for translation

livebooks_external/04-gettext.livemd

4. Using gettext for translation

Mix.install([
  :gettext
])
Resolving Hex dependencies...
Resolution completed in 0.072s
New:
  expo 0.4.1
  gettext 0.22.3
* Getting gettext (Hex package)
* Getting expo (Hex package)
==> expo
Compiling 2 files (.erl)
Compiling 21 files (.ex)
Generated expo app
==> gettext
Compiling 17 files (.ex)
Generated gettext app
:ok

Setup .po translation files

The gettext workflow relies heavily on the filesystem: Each supported locale must have a directory in a specific place. Inside of this directory, gettext expects to find translation files (ending in .po), named for a particular domain (usually ‘default’) that contain translation strings in a specific format.

Here we generate a sample translation file for gettext, but usually, this will be done with 3rd-party tooling, like http://poedit.net/ or https://poeditor.com.

# find the current directory, where the livebook is running
{current_dir, _} = System.cmd("pwd", [])

# create a new directory for French translation files
System.cmd("mkdir", ["-p", "priv/gettext/fr_FR/LC_MESSAGES"])

# create a new ".po" translation file
sample_po_translation_file = """
msgid "Here is one string to translate"
msgstr "Voici une chaîne à traduire"

msgid "404 error"
msgstr "erreur 404"
"""

{:ok, file} = File.open("priv/gettext/fr_FR/LC_MESSAGES/default.po", [:write, :utf8])
IO.write(file, sample_po_translation_file)
:ok

Once the translation files are in place, they are parsed and baked into your application by gettext at compile-time. Below, we define a new gettext ‘backend’ module, which triggers compilation.

# define a gettext 'backend model'
defmodule DemoApp.Gettext do
  use Gettext, otp_app: :foo
end
{:module, DemoApp.Gettext, <<70, 79, 82, 49, 0, 0, 47, ...>>, :ok}

Translation functions

TODO: explain these

import DemoApp.Gettext

Gettext.put_locale("fr_FR")

# simple message
gettext("Hello world")
|> IO.inspect()

gettext("404 error")
|> IO.inspect()

gettext("Here is one string to translate")
|> IO.inspect()

# plural message
number_of_apples = 4

ngettext("The apple is ripe", "The apples are ripe", number_of_apples)
|> IO.inspect()

# domain-based message
dgettext("errors", "Here is an error message to translate")
|> IO.inspect()

:ok
"Hello world"
"erreur 404"
"Voici une chaîne à traduire"
"The apples are ripe"
"Here is an error message to translate"
:ok