Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


I18n made easy for web sites written with eliom


usage: ocsigen-i18n-generator [options] [< input] [> output]
  --languages         Comma-separated languages (e.g. en,fr-fr, or Foo.Fr,Foo.Us if using external types). Must be ordered as in source TSV file.
  --default-language  Set the default language (default is the first one in --languages).
  --input-file        TSV file containing keys and translations. If option is omited or set to -, read on stdin.
  --ouput-file        File TSV file containing keys and translations. If option is omitted or set to -, write on stdout.
  --external-type     Values passed to --languages option come from a predefined type (do not generate the type nor from/to string functions).
  --primary           Generated file is secondary and depends on given primary file.
  -help               Display this list of options
  --help              Display this list of options


The ppx supports two general forms of constructions:

  • I18n entries in the 'default' file
  • I18n entries in a given module

You can use ocsigen-i18n-generator to generate multiple .eliom files from different TSV files. One of those will be the "default" one.

Use the -ppx 'ocsigen-i18n-rewriter --default-module DEFAULT' where DEFAULT is the name of the module generated with ocsigen-i18n-generator you wish to use as a default for all extension expressions (basename of the output file)

This will call the right function turning [%i18n foo] into (), [%i18n ~x:"foo"] into ~x:"foo" ()] and so on...

To specify a different module from the default one, you can do so using expressions such as these:

  • [%i18n] will become ()
  • [%i18n ~x:[%i18n]] will become ~x:( ()) ()

Because the rewriter infers your module from the module-path of your expression, it needs to make the assumption that a module named S will always be the one generated by ocsigen-i18n-generator for strings. Do not name your i18n file s.tsv. It won't be compatible.

Affixing the module names

Because the ppx already forces you to i18n in the expression, and because most projects will want to keep sane files with i18n in their names, it would be likely to end up with expressions like [%i18n I18n_a.entry].

This is redundant and heavy. So, if you like, you can auto-prefix and auto-suffix your module names.

Calling the rewriter with -ppx 'ocsigen-i18n-rewriter --prefix Pr_ --suffix _i18n --default-module DEFAULT' will prefix and suffix all custom modules (i.e. not the DEFAULT one) with Pr_ and _i18n.

As such, [%i18n] will become (), allowing for clearer and more readable expressions.

The prefix must begin with a capital letter, to make it a legit module name start.

If you use these options, note that your file will need to account for the capital in the middle part. [%i18n Module.entry] still needs Module to be a module name.


opam pin add ocsigen-i18n
opem install ocsigen-i18n

How to

Templating system

Define your translations into a tsv file. The first column is the key to use (i.e. the name of the OCaml variable to use in your code). The next columns are the translation for each language you want to use.

foo	This is a simple key.	Ceci est une clé toute simple.
bar	I am {{x}}.	Je suis {{x}}.
baz	There {{{c?are||is}}} apple{{{c?s||}}} here!	Il y a {{{c?des||une}}} pomme{{{c?s||}}} ici !
bu	I am {{x %s}} ({{n %d}}).	Je suis {{x %s}} ({{n %d}}).
  • {{x}} defines a variable labeled ~x
  • {{x %d}} defines a variable labeled ~x, and the %d format is used to display x as a string.
  • {{x?a||b}} defines an optional boolean value ?x. If x is true then a will be displayed. If it is false (which is the default), then b is chosen.

Using the templates

[%i18n foo]
[%i18n bar ~x:[%i18n a_human]]
[%i18n bar ~x:[ pcdata "Jean-Michel ("
              ; pcdata @@ string_of_int id
              ; pcdata ")" ] ]
[%i18n baz]
[%i18n baz ~c:(nb > 1)]
[%i18n bu ~x:"Jean-Michel" ~n:id ]

This will generate an HTML fragment (a list of elements). If you want a string instead of a list of elements, prefix the variable name by S., e.g. [%i18n ~s:[%i18n S.a_human]].

Notes about the templates

A conditional value {{{c?if_true||if_false}}} will generate a function taking an optional parameter ?(c=false) to define if if_true or if_false needs to be printed.

Languages does not need to use the same labeled variables. The compiler will generate a function taking all the parameters it can detect when parsing the template.

Variable name used twice refers to the same argument.


No description, website, or topics provided.




No packages published