Glossa
Glossa is a language localisation library.
Functionality
It can be divided into two categories.
- Const map: Load localisation data efficiently through constant data.
- Description: Convert configuration files into constant (
const fn) code at compile time and read constant data at runtime. - Pros: Efficient
- Cons:
- Requires
codegen, which may result in some redundant code after expansion. - Currently only supports simple key-value (K-V) pairs.
- Requires
- Description: Convert configuration files into constant (
- Flunt
- Description: Manage Fluent resources at runtime.
- Pros: Fluent syntax may be more suitable for localisation.
- Cons: Requires more resources than
const map.
Note: Fluent also supports loading localisation resources (localised files) at compile time, but data needs to be parsed at runtime.
The former is just the simple K-V pair that uses some const maps from phf to store data. Because it's simple, it's efficient.
The two types of functionalities are independent of each other. For the latter, please read Fluent.md.
Codegen
Use a code generator to generate code.
glossa-codegen has the following features:
- yaml
- Enabled by default.
- The default file extension is "yaml" or "yml"
- ron
- The default ext is "ron"
- toml
- The ext is "toml"
- json
- ext: "json"
This corresponds to different types of configuration files. You can enable all features or add them as needed.
By default, the file type is determined based on the file name extension, and the map name (table name) is set based on the file name. Whether deserialisation is needed at compile-time is determined by the enabled feature.
Assuming there are two files under the directory assets/l10n/en, named test.yaml and test.yml, then we can consider them to have the same name.
Resulting in two tables(maps):
- test
- test.yml
When using
.get()withMapLoader, you need to pass in the map-name
To avoid this situation, it is recommended to use different names for different files.
Preparations
Before writing build.rs, we need to prepare the localisation resource files.
de (Deutsch, Lateinisch, Deutschland):
- "assets/l10n/de/error.yaml"
text-not-found: Kein lokalisierter Text gefunden
en (English, Latin, United States):
- "assets/l10n/en/error.yaml"
text-not-found: No localized text found
en-GB (English, Latin, Great Britain):
assets/l10n/en-GB/error.yaml
text-not-found: No localised text found
es (español, latino, España):
assets/l10n/es/error.yaml
text-not-found: No se encontró texto localizado
pt (português, latim, Brasil)
assets/l10n/pt/error.yaml
Note: "pt" refers to "Portuguese (Brazil)", not "Portuguese (Portugal)" (português, Portugal).
text-not-found: Nenhum texto localizado encontrado
build.rs
First, add the compile-time dependency:
Then start creating build.rs.
This file is at the same level as Cargo.toml.
For a simple single-project structure:
.
├── assets
├── build.
├──
├──
├── src
└── target
A slightly more complex multi-project structure:
.
├── assets
│ └── l10n
├──
├──
├── codegen
│ ├──
│ ├── src
│ └── tests
├── glossa
│ ├── build.
│ ├──
│ └── src
├── target
└── tests
Of course, you can also specify the path to build.rs manually, instead of using the default.
build.rs:
use ;
use ;
After running cargo b, the code will be generated automatically. If your l10n rs file is src/assets/localisation.rs, you will also need to manually add pub(crate) mod assets; to lib.rs or main.rs (depending on the type of crate you have).
Get Text
Now that the code has been generated, let's write a function to test it!
But before that, we need to add some dependencies.
The test function is as follows:
If your system language is "en", the test should pass.
Note that locale_hashmap() is not a const fn but a regular function.
However, this does not mean that it is particularly expensive.
The time complexity of HashMap query operation is O(1).
Its value points to a sub-map, and all sub-maps and their sub-maps are consts.
In addition, if the ahash feature is enabled, the RandomState of ahash will be used by default instead of the std::collections.
You can also use OnceCell to create global static data, creating data only once.
pub
Wait a minute, don't waste time on these things, our previous test failed.
All right, let's revisit what we did before.
We have previously created localisation resource files for German, Spanish and Portuguese.
Firstly, it will automatically detect the system language. If the localisation resource does not exist, it will automatically use a fallback chain. If the localisation resource exists and your system language is not English, then the above test will fail.
Let's continue to test:
let loader = locales;
let msg = loader.get?;
Assuming your language is German (de-Latn-DE)
assert_eq!;
Spanish (es-Latn-ES)
assert_eq!;
Portuguese (pt-Latn-BR)
assert_eq!;