safflower
A Statically Allocated Format-Friendly Localiser
Purpose
safflower aims to be a easy-to-use localising crate for rust projects, providing the simplest possible way to interface with text in multiple languages or dialects (or any other kind of variation).
Usage
By using the load! macro, the source text is loaded in all variations. The simplest way to access it is then through the text! macro, which automatically picks the variant corresponding to the currently set locale.
Features
Minimal setup
The load! macro generates code that statically allocates the text you want to use. This means that once your code has been compiled nothing has to be checked for errors, and nothing has to be loaded. There is some slight overhead for this, of course, see benchmarks below. Specifically, if your code compiles, it is guaranteed that:
- the source files exist and the text could be read;
- all entries could be parsed;
- every text entry uses every declared locale;
- every text entry uses the same number of parameters in each locale;
- every key is accessible as an identifier (no need for options or results).
Flexibility and limitations
The aim is to be as flexible as possible, while requiring the
least amount of time and user effort. The intented use
is for text localisation, i.e. providing UI text in different
languages or dialects, but you might find a different use.
Often having more options means weaker assumptions, and so, for
instance, it is not possible to not have any locales. It is also
not possible to have a vector of strings as a value, though that
might change if deemed useful and uncostly.
If there's any feature you feel is missing, please submit an
issue on GitHub or drop an email.
Formattability
The text can also be formatted, following rust's usual
format! syntax.
safflower checks that all locale
variants in an entry use the same number of parameters, and with
the same names. It does not check how you format them however.
Due to practical limitations, unnamed or numbered parameters
like {} or
{0} are given names when parsed,
starting at `arg0` and counting upwards. This means a line
containing both an unnamed or numbered parameter and a parameter
named e.g. `arg0` will cause a conflict. Since this is a rather
minor issue, and one should probably avoid not naming parameters
in the first place, there is no plan to do anything about it;
the effort and possible computational overhead is not worth it.
Hierarchy
Sometimes it may be nice (or necessary) to split text entries up. There are two, non-exclusive ways to do so.
The first is to use separate files with
!include, e.g. to have
only one locale per file
!include en.txt it.txt
# file en.txt
!locales en
greet: en "Hi!"
# file it.txt
!locales it
greet: it "Ciao!"
The second is to create scopes with
!scope, e.g. to group texts by use
case.
!scope menu-items
new-file:
en "New"
it "Nuovo"
!scope errors
empty-field:
en "\"{field}\" cannot be empty"
it "\"{field}\" non può essere vuoto"
It should be noted that including a file after creating a scope will import that file into that scope. Every scope also re-imports the Locale enum, so that it is available without traversing the whole path.
Benchmarks
Coming soon...