Skip to main content

Module l10n

Module l10n 

Source
Expand description

Localization service, sources and other types.

Localized text is declared using the l10n! macro, it provides a read-only text variable that automatically updates to be best localized text available given the current loaded localization and the app language.

use zng::prelude::*;

let click_count = var(0u32);
Window! {
    title = l10n!("window-title", "Window Title");
    child = Button! {
        on_click = hn!(click_count, |_| click_count.set(click_count.get() + 1));
        child = Text!(l10n!("click-count", "Clicked {$n} times", n = click_count.clone()));
    };
}

In the example above declares two localization messages, “window.title” and “btn.click_count”, if these messages are localized for the current language the localized text is used, otherwise the provided fallback is used.

The L10N service can be used to set the app language and load localization resources. The example below sets the language to en-US and loads localization from a directory using L10N.load_dir.

use zng::prelude::*;

APP.defaults().run_window("main", async {
    // start loading localization resources
    L10N.load_dir(zng::env::res("l10n"));
    // set the app language, by default is the system language
    L10N.app_lang().set(lang!("en-US"));
    // preload the localization resources for a language
    L10N.wait_first(lang!("en-US")).await;

    Window! {
        // ..
    }
});

The service also supports embedded localization resources in the .tar and .tar.gz formats using L10N.load_tar, see the localize example for more details. You can also implement more container formats using L10N.load.

§Fluent

The localization files are in the Fluent format. Fluent empowers translators to script things like plural forms, for this reason a localization file should be provided even for the same language the l10n! fallback text is written in.

click-count = {$n ->
    [one] Clicked {$n} time
    *[other] Clicked {$n} times
}

The example above demonstrates a localized message that provides plural alternatives for the English language.

§Scraper

The cargo zng l10n tool can be used to generate a Fluent file from source code, the Fluent file can be used as a template for translators, it will include the fallback text and comments written close the key declaration.

use zng::prelude::*;

// l10n-### This standalone comment is added to the scraped template file.

let click_count = var(0u32);
Window! {
    title = l10n!("window-title", "Window Title");
    child = Button! {
        on_click = hn!(click_count, |_| click_count.set(click_count.get() + 1));
        // l10n-# This comment is added to the `"click-count"` entry.
        child = Text!(l10n!("click-count", "Clicked {$n} times", n = click_count.clone()));
    };
}

When the example above is scrapped it generates:

### This standalone comment is added to all scraped template files.

# This comment is added to the `"click-count"` entry.
click-count = Clicked {$n} times

See the l10n! documentation for a full explanation of how the Scraper converts comments and the l10n! calls into Fluent files.

§Commands

Commands metadata can be localized and scrapped, to enable this set l10n!: on the command! declarations.

If the first metadata is l10n!: the command init will attempt to localize the other string metadata. The cargo zng l10n command line tool scraps commands that set this special metadata.

command! {
    pub static FOO_CMD {
        l10n!: true,
        name: "Foo!",
        info: "Does the foo thing",
    };
}

The example above will be scrapped as:

FOO_CMD =
    .name = Foo!
    .info = Does the foo thing.

The l10n!: meta can also be set to a localization file name:

command! {
    pub static FOO_CMD {
        l10n!: "file",
        name: "Foo!",
    };
}

The example above is scrapped to {l10n-dir}/{lang}/file.ftl files.

§Limitations

Interpolation is not supported in command localization strings.

The l10n!: value must be a textual literal, that is, it can be only a string literal or a bool literal, and it cannot be inside a macro expansion.

§Dependency Localization

The cargo zng l10n tool copies all localization files from dependency crates by default. The Fluent files are placed in dir/{lang}/deps/*/*/*.ftl, the L10N service knows to search these directories structure for localization.

Note that dependency crates are not scrapped, the library crate authors are expected to scrap (and translate) text to a {crate}/l10n directory, beside the {crate}/Cargo.toml.

The copied dependency resources are excluded from Git source control by default, the recommended workflow is to rerun cargo zng l10n after each cargo update. Projects created using cargo zng new can just run cargo do update, that is a shorthand for:

cargo update
cargo zng l10n --no-local --no-pkg --output res/l10n

§Packaging

When packaging a release build for publish you want to only include the dependency resources for the locales supported by your application. The easiest way to do this is cargo zng res with a .zr-l10n tool call, it will automatically filter out languages that only have dependency resources and also. Call cargo zng res --tool sh to read detailed help.

§Subsetting

Your app may not use all localization resources from dependencies, with some work you can collect a subset allow list that can be used by .zr-l10n to only package the entries used, in this mode the dependency Fluent files are edited down to include only the text actually used by the app.

The easiest way to get started is to build with the "l10n_usage_recorder" Cargo feature, run the app and visit every screen and state that uses localization text. The subset profile is saved to res/optimization-profiles/zng-ext-l10n.rec.subset by default, you can change the location by setting the ZNG_L10N_PROFILE_FILE env var.

The profile is a text file with format:

# comments

{dependency}//{file}/{id}.{attribute}

The dependency is the crate package name, {file}/{id}.{attribute} is the same key syntax used by l10n!.

The generated file will has a comment header with instruction on how to manually add icons.

The profile file can be added to source control, the recorded entries are sorted so changes are stable.

§Full API

See zng_ext_l10n for the full localization API.

Macros§

l10n
Gets a variable that localizes and formats the text in a widget context.
lang
Compile-time validated Lang value.

Structs§

L10N
Localization service.
L10nDir
Represents localization resources synchronized from files in a directory.
L10nMessageBuilder
Localized message variable builder.
L10nTar
Represents localization resources loaded from a .tar or .tar.gz container.
Lang
Identifies the language, region and script of text.
LangFilePath
Localization resource file path in the localization directory.
LangMap
Represents a map of Lang keys that can be partially matched.
LangResource
Handle to a localization resource.
LangResources
Handle to multiple localization resources.
Langs
List of languages, in priority order.
NilL10nSource
Localization source that is never available.
SwapL10nSource
Represents localization source that can swap the actual source without disconnecting variables taken on resources.

Enums§

L10nArgument
Represents an argument value for a localization message.
LangResourceStatus
Status of a localization resource.

Statics§

LANG_VAR
Language of text in a widget context.

Traits§

L10nSource
Represents a localization data source.