zng/
l10n.rs

1//! Localization service, sources and other types.
2//!
3//! Localized text is declared using the [`l10n!`] macro, it provides a read-only text variable that automatically
4//! updates to be best localized text available given the current loaded localization and the app language.
5//!
6//! ```
7//! use zng::prelude::*;
8//! # let _scope = APP.defaults();
9//!
10//! let click_count = var(0u32);
11//! # let _ =
12//! Window! {
13//!     title = l10n!("window-title", "Window Title");
14//!     child = Button! {
15//!         on_click = hn!(click_count, |_| click_count.set(click_count.get() + 1));
16//!         child = Text!(l10n!("click-count", "Clicked {$n} times", n = click_count.clone()));
17//!     };
18//! }
19//! # ;
20//! ```
21//!
22//! In the example above declares two localization messages, "window.title" and "btn.click_count", if
23//! these messages are localized for the current language the localized text is used, otherwise the provided
24//! fallback is used.
25//!
26//! The [`L10N`] service can be used to set the app language and load localization resources. The example below
27//! sets the language to en-US and loads localization from a directory using [`L10N.load_dir`].
28//!
29//! ```no_run
30//! use zng::prelude::*;
31//!
32//! APP.defaults().run_window(async {
33//!     // start loading localization resources
34//!     L10N.load_dir(zng::env::res("l10n"));
35//!     // set the app language, by default is the system language
36//!     L10N.app_lang().set(lang!("en-US"));
37//!     // preload the localization resources for a language
38//!     L10N.wait_first(lang!("en-US")).await;
39//!     
40//!     Window! {
41//!         // ..
42//!     }
43//! });
44//! ```
45//!
46//! The service also supports embedded localization resources in the `.tar` and `.tar.gz` formats using
47//! [`L10N.load_tar`], see the [localize example] for more details. You can also implement more container formats using [`L10N.load`].
48//!
49//! [`L10N.load_dir`]: crate::l10n::L10N::load_dir
50//! [`L10N.load_tar`]: crate::l10n::L10N::load_tar
51//! [`L10N.load`]: crate::l10n::L10N::load
52//! [localize example]: https://github.com/zng-ui/zng/blob/main/examples/localize/build.rs
53//!
54//! # Fluent
55//!
56//! The localization files are in the [Fluent](https://projectfluent.org/) format. Fluent empowers translators to
57//! script things like plural forms, for this reason a localization file should be provided even for the same
58//! language the `l10n!` fallback text is written in.
59//!
60//! ```ftl
61//! click-count = {$n ->
62//!     [one] Clicked {$n} time
63//!     *[other] Clicked {$n} times
64//! }
65//! ```
66//!
67//! The example above demonstrates a localized message that provides plural alternatives for the English language.
68//!
69//! # Scraper
70//!
71//! The `cargo zng l10n` tool can be used to generate a Fluent file from source code, the Fluent file can be
72//! used as a template for translators, it will include the fallback text and comments written close the key
73//! declaration.
74//!
75//! ```
76//! use zng::prelude::*;
77//! # let _scope = APP.defaults();
78//!
79//! // l10n-### This standalone comment is added to the scraped template file.
80//!
81//! let click_count = var(0u32);
82//! # let _ =
83//! Window! {
84//!     title = l10n!("window-title", "Window Title");
85//!     child = Button! {
86//!         on_click = hn!(click_count, |_| click_count.set(click_count.get() + 1));
87//!         // l10n-# This comment is added to the `"click-count"` entry.
88//!         child = Text!(l10n!("click-count", "Clicked {$n} times", n = click_count.clone()));
89//!     };
90//! }
91//! # ;
92//! ```
93//!
94//! When the example above is scrapped it generates:
95//!
96//! ```ftl
97//! ### This standalone comment is added to all scraped template files.
98//!
99//! # This comment is added to the `"click-count"` entry.
100//! click-count = Clicked {$n} times
101//! ```
102//!
103//! See the [`l10n!`] documentation for a full explanation of how the Scraper converts comments and the
104//! `l10n!` calls into Fluent files.
105//!
106//! [`l10n!`]: crate::l10n::l10n
107//!
108//! # Commands
109//!
110//! Commands metadata can be localized and scrapped, to enable this set `l10n!:` on the [`command!`](zng::event::command) declarations.
111//!
112//! If the first metadata is `l10n!:` the command init will attempt to localize the other string metadata. The `cargo zng l10n`
113//! command line tool scraps commands that set this special metadata.
114//!
115//! ```
116//! # use zng_app::{event::{command, CommandNameExt, CommandInfoExt}, shortcut::{CommandShortcutExt, shortcut}};
117//! command! {
118//!     pub static FOO_CMD = {
119//!         l10n!: true,
120//!         name: "Foo!",
121//!         info: "Does the foo thing",
122//!     };
123//! }
124//! ```
125//!
126//! The example above will be scrapped as:
127//!
128//! ```ftl
129//! FOO_CMD =
130//!     .name = Foo!
131//!     .info = Does the foo thing.
132//! ```
133//!
134//! The `l10n!:` meta can also be set to a localization file name:
135//!
136//! ```
137//! # use zng_app::{event::{command, CommandNameExt, CommandInfoExt}, shortcut::{CommandShortcutExt, shortcut}};
138//! command! {
139//!     pub static FOO_CMD = {
140//!         l10n!: "file",
141//!         name: "Foo!",
142//!     };
143//! }
144//! ```
145//!
146//! The example above is scrapped to `{l10n-dir}/{lang}/file.ftl` files.
147//!
148//! ## Limitations
149//!
150//! Interpolation is not supported in command localization strings.
151//!
152//! 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
153//! inside a macro expansion.
154//! # Full API
155//!
156//! See [`zng_ext_l10n`] for the full localization API.
157
158pub use zng_ext_l10n::{
159    IntoL10nVar, L10N, L10nArgument, L10nDir, L10nMessageBuilder, L10nSource, L10nTar, LANG_VAR, Lang, LangFilePath, LangMap, LangResource,
160    LangResourceStatus, LangResources, Langs, NilL10nSource, SwapL10nSource, l10n, lang,
161};