#localization #string #internationalization #run-time #translating #macro #language

crowbook-intl

An internationalization library to localize strings, translating them according to runtime option, using macros

3 unstable releases

Uses old Rust 2015

0.2.1 Mar 4, 2017
0.2.0 Dec 23, 2016
0.1.0 Nov 18, 2016

#1813 in Rust patterns

Download history 5/week @ 2023-11-30 1/week @ 2023-12-07 1/week @ 2023-12-14 3/week @ 2023-12-21 6/week @ 2023-12-28 20/week @ 2024-01-04 18/week @ 2024-01-11 7/week @ 2024-01-25 21/week @ 2024-02-01 21/week @ 2024-02-08 36/week @ 2024-02-15 54/week @ 2024-02-22 53/week @ 2024-02-29 34/week @ 2024-03-07 41/week @ 2024-03-14

185 downloads per month
Used in 2 crates

MPL-2.0 license

35KB
616 lines

crowbook-intl

A library to localize strings, translating them according to runtime options.

Basically, this library allows your project to generate a lformat! macro, that behaves similarly to format!, except the message string (the first argument) might get translated (if you can find the appropriate string for the language).

Usage

First, you'll need to add the following to your Cargo.toml file:

build = "build.rs"

[build-dependencies]
crowbook-intl = "0.1.0"

[dependencies]
crowbook-intl-runtime = "0.1.0"

You'll then need to create the build.rs file, which can look like this:

extern crate crowbook_intl;
use crowbook_intl::{Localizer, Extractor};

fn main() {
    // Generate a `lang/default.pot` containing strings used to call `lformat!`
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src")).unwrap();
    extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/default.pot")).unwrap();

    // Generate the `localize_macros.rs` file
    let mut localizer = Localizer::new(&extractor);
    // Use env::var instead of env! to avoid problems when cross-compiling
    let dest_path = Path::new(&env::var("OUT_DIR").unwrap())
       .join("localize_macros.rs");
    localizer.write_macro_file(dest_path).unwrap();
}

This will create a localize_macros.rs at build time somewhere in OUT_DIR, containing the lformat! macro. To actually use this macro, you have to create a src/localize_macros.rs file that includes it:

include!(concat!(env!("OUT_DIR"), "/localize_macros.rs"));

To use it, the last step is to modify your src/lib/lib.rs file:

extern crate crowbook_intl_runtime;
#[macro_use] mod localize_macros;

Once this is done, you can start replacing your calls to format! with calls to lformat!.

In order to get translation, you'll need to actually translate the strings in separate files, and set your build.rs to load them.

E.g., if you have the following code:

println!("{}", lformat!("Hello, world!"));

and you want it translated in french, you'll have to create a lang/fr.po file from the lang/default.pot file containing:

msgid "Hello, world!";
msgstr "Bonjour le monde !";

And load it in your build.rs file:

let mut localizer = Localizer::new();
localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/fr.mp"))).unwrap();
(...)

Once this is done, you can use the localize_macros::set_lang function to switch the language at runtime:

use crowbook_intl_runtime::set_lang;
set_lang("en");
println!("{}", lformat!("Hello, world!")); // prints "Hello, world!"
set_lang("fr");
println!("{}", lformat!("Hello, world!")); // prints "Bonjour le monde !"

Updating your translation

When you add new strings that need to be translated (by more calls to lformat!), or when you change the content of existing strings, you can use Gettext's msgmerge and msgcmp commands to update your translation. While it is not guaranteed that the formats are strictly identical, it should work. (That is, it is a bug if it doesn't; but at this stage, this library is absolutely not guaranteed to be bug-free.)

Known limitations and bugs

  • Currently, crowbook-intl doesn't handle correctly raw string literals in lformat! (they won't be translated correctly).
  • Multiple calls to the same string, but formatted differently (e.g. using a backslash before a newline to separate a string on multiple lines) will also cause problems.

Warning

In case the complexity of the operation didn't discourage you, I should warn you that this library is highly experimental at this time.

License

This is free software, published under the Mozilla Public License, version 2.0.

Documentation

See the documentation on docs.rs.

ChangeLog

See the ChangeLog file.

Author

Élisabeth Henry liz.henry@ouvaton.org.

Dependencies

~3.5MB
~74K SLoC