1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*!
# JSON Get Text
This library reads texts from JSON, usually for internationalization (i18n).
Each **key** is a locale (for example `en_US` or `zh_TW`), and each locale maps **text names** to **values**. A value can be any JSON value, not only a string.
## Example
```rust,ignore
use json_gettext::{get_text, static_json_gettext_build};
let ctx = static_json_gettext_build!(
"en_US";
"en_US" => "langs/en_US.json",
"zh_TW" => "langs/zh_TW.json",
)
.unwrap();
assert_eq!("Hello, world!", get_text!(ctx, "hello").unwrap());
assert_eq!("哈囉,世界!", get_text!(ctx, "zh_TW", "hello").unwrap());
```
The argument before `;` is the **default key**. Every other key may only contain text names that also exist in the default key; this is checked when the context is built. To drop such extra texts instead of failing, build with [`JSONGetTextBuilder`] and call `allow_extra_texts(true)`.
## Looking Up Texts
The lookup methods differ in how they fall back to the default key:
- `get_text(text)` reads a text from the default key.
- `get_text_with_key(key, text)` reads a text from `key`, and falls back to the default key when that single text is missing.
- `get_multiple_text_with_key(key, &[text, ...])` applies the same per-text fallback to many texts at once.
- `get(key)` returns the whole map of texts that `key` owns. Missing texts are **not** filled in from the default key; only when `key` itself does not exist is the default key's map returned instead.
The `get_text!` macro is a shortcut with three forms: `get_text!(ctx, text)`, `get_text!(ctx, key, text)`, and `get_text!(ctx, key, text1, text2, ...)`.
## Features
### Key Backends (mutually exclusive)
By default a key is an arbitrary `String`, matched by exact string comparison. If your keys are locale tags, you can enable one of the features below to store keys as fixed-size `Copy` values from the [`unic-langid`](https://crates.io/crates/unic-langid) crate. This makes key comparison faster and normalizes the tag format, so `en-US` and `en_US` become the same key.
| Feature | `Key` type | Example tag | Use when |
|---------|------------|-------------|----------|
| *(none)* | `Key(String)` | `en_US` | keys are arbitrary strings |
| `locale` | `Key(Language, Option<Region>)` | `en_US` | you key by language **and** region |
| `language` | `Key(Language)` | `en` | you key by language only |
| `region` | `Key(Region)` | `US` | you key by region only |
These three features each redefine `Key`, so **at most one** may be enabled. Enabling more than one, or enabling the internal `langid` feature on its own, fails to compile with a message telling you what to do.
When a langid backend is enabled, use the `key!` macro to build a `Key` from a string literal at compile time:
```rust,ignore
use json_gettext::{key, Key};
let key: Key = key!("en_US");
```
### `regex`
Enables `get_filtered_text` and `get_filtered_text_with_key`, which return every text whose **name** matches a [`Regex`](https://crates.io/crates/regex). These methods do not fall back to the default key.
### `rocket`
Integrates with the [Rocket](https://rocket.rs) web framework. See the section below.
## Rocket Support
Enable the `rocket` feature, then build the context with `static_json_gettext_build_for_rocket` instead of `static_json_gettext_build`. It registers a `JSONGetTextManager`, which derefs to `JSONGetText`.
```toml
[dependencies.json-gettext]
version = "*"
features = ["rocket"]
```
In debug builds the manager watches the JSON files and reloads them when they change, so translations can be edited without recompiling. In release builds the JSON is embedded into the binary and is never reloaded.
```rust,ignore
#[macro_use]
extern crate rocket;
use json_gettext::{get_text, static_json_gettext_build_for_rocket, JSONGetTextManager};
use rocket::response::Redirect;
use rocket::State;
#[get("/")]
fn index(ctx: &State<JSONGetTextManager>) -> Redirect {
Redirect::temporary(uri!(hello(lang = ctx.get_default_key())))
}
#[get("/<lang>")]
fn hello(ctx: &State<JSONGetTextManager>, lang: String) -> String {
format!("Ron: {}", get_text!(ctx, lang, "hello").unwrap().as_str().unwrap())
}
#[launch]
fn rocket() -> _ {
rocket::build()
.attach(static_json_gettext_build_for_rocket!(
"en_US";
"en_US" => "langs/en_US.json",
"zh_TW" => "langs/zh_TW.json"
))
.mount("/", routes![index, hello])
}
```
### Rocket with a langid backend
With a langid backend, pass `Key` values (built with `key!`) instead of strings.
```rust,ignore
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_accept_language;
use json_gettext::{get_text, key, static_json_gettext_build_for_rocket, JSONGetTextManager, Key};
use rocket::State;
use rocket_accept_language::unic_langid::subtags::Language;
use rocket_accept_language::AcceptLanguage;
const LANGUAGE_EN: Language = language!("en");
#[get("/")]
fn index(ctx: &State<JSONGetTextManager>, accept_language: &AcceptLanguage) -> String {
let (language, region) =
accept_language.get_first_language_region().unwrap_or((LANGUAGE_EN, None));
format!("Ron: {}", get_text!(ctx, Key(language, region), "hello").unwrap().as_str().unwrap())
}
#[launch]
fn rocket() -> _ {
rocket::build()
.attach(static_json_gettext_build_for_rocket!(
key!("en");
key!("en") => "langs/en_US.json",
key!("zh_TW") => "langs/zh_TW.json",
))
.mount("/", routes![index])
}
```
*/
// The `locale`, `language`, and `region` features each redefine the `Key` type, so at most one may be enabled.
compile_error!;
// `langid` is only an internal umbrella feature; enabling it alone leaves the `Key` type undefined.
compile_error!;
pub extern crate serde_json;
pub extern crate regex;
pub extern crate unic_langid;
pub extern crate manifest_dir_macros;
pub use *;
pub use *;
pub use *;
pub use *;
use DebuggableMutate;
pub use LanguageIdentifierError;
pub use ParserError;
pub use *;