Skip to content

Commit b00eb34

Browse files
committed
Switch to unic_langid for Language Identifier Management
1 parent 88c7bf9 commit b00eb34

File tree

21 files changed

+207
-147
lines changed

21 files changed

+207
-147
lines changed

fluent-bundle/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ keywords = ["localization", "l10n", "i18n", "intl", "internationalization"]
1818
categories = ["localization", "internationalization"]
1919

2020
[dependencies]
21-
fluent-locale = "^0.4.1"
21+
fluent-locale = "^0.6.0"
2222
fluent-syntax = "^0.9"
2323
failure = "^0.1"
2424
failure_derive = "^0.1"
25-
intl_pluralrules = "^1.0"
25+
intl_pluralrules = "^1.1.0"
2626
rental = "^0.5.4"
27-
smallvec = "0.6.10"
27+
smallvec = "^0.6.10"
28+
unic-langid = "^0.3.0"
2829

2930
[dev-dependencies]
3031
criterion = "^0.2"

fluent-bundle/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ Usage
2323

2424
```rust
2525
use fluent_bundle::{FluentBundle, FluentResource};
26+
use std::convert::TryFrom;
27+
use unic_langid::LanguageIdentifier;
2628

2729
fn main() {
2830
let ftl_string = "hello-world = Hello, world!".to_owned();
2931
let res = FluentResource::try_new(ftl_string)
3032
.expect("Could not parse an FTL string.");
3133

32-
let mut bundle = FluentBundle::new(&["en-US"]);
34+
let langid_en = LanguageIdentifier::try_from("en").expect("Parsing failed.");
35+
let mut bundle = FluentBundle::new(&[langid_en]);
3336

3437
bundle.add_resource(&res)
3538
.expect("Failed to add FTL resources to the bundle.");

fluent-bundle/benches/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn resolver_bench(c: &mut Criterion) {
8585
let res =
8686
FluentResource::try_new(source.to_owned()).expect("Couldn't parse an FTL source");
8787
let ids = get_ids(&res);
88-
let mut bundle = FluentBundle::new(&["x-testing"]);
88+
let mut bundle = FluentBundle::default();
8989
bundle
9090
.add_resource(res)
9191
.expect("Couldn't add FluentResource to the FluentBundle");

fluent-bundle/examples/external_arguments.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use fluent_bundle::{FluentBundle, FluentResource, FluentValue};
22
use std::collections::HashMap;
3+
use std::convert::TryFrom;
4+
use unic_langid::LanguageIdentifier;
35

46
fn main() {
57
let ftl_string = String::from(
@@ -14,7 +16,8 @@ unread-emails =
1416
",
1517
);
1618
let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string.");
17-
let mut bundle = FluentBundle::new(&["en"]);
19+
let langid_en = LanguageIdentifier::try_from("en").expect("Parsing failed.");
20+
let mut bundle = FluentBundle::new(&[langid_en]);
1821
bundle
1922
.add_resource(res)
2023
.expect("Failed to add FTL resources to the bundle.");

fluent-bundle/examples/functions.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use fluent_bundle::{FluentBundle, FluentResource, FluentValue};
2+
use std::convert::TryFrom;
3+
use unic_langid::LanguageIdentifier;
24

35
fn main() {
46
// We define the resources here so that they outlive
@@ -10,7 +12,8 @@ fn main() {
1012
let res2 = FluentResource::try_new(ftl_string2).expect("Could not parse an FTL string.");
1113
let res3 = FluentResource::try_new(ftl_string3).expect("Could not parse an FTL string.");
1214

13-
let mut bundle = FluentBundle::new(&["en-US"]);
15+
let langid_en_us = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
16+
let mut bundle = FluentBundle::new(&[langid_en_us]);
1417

1518
// Test for a simple function that returns a string
1619
bundle

fluent-bundle/examples/hello.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use fluent_bundle::{FluentBundle, FluentResource};
33
fn main() {
44
let ftl_string = String::from("hello-world = Hello, world!");
55
let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string.");
6-
let mut bundle = FluentBundle::new(&["en-US"]);
6+
let mut bundle = FluentBundle::default();
77
bundle
88
.add_resource(&res)
99
.expect("Failed to add FTL resources to the bundle.");

fluent-bundle/examples/message_reference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ bazbar = { baz } Bar
1010
);
1111
let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string.");
1212

13-
let mut bundle = FluentBundle::new(&["x-testing"]);
13+
let mut bundle = FluentBundle::default();
1414
bundle
1515
.add_resource(res)
1616
.expect("Failed to add FTL resources to the bundle.");

fluent-bundle/examples/selector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ hello-world2 = Hello { $name ->
1616
",
1717
);
1818
let res = FluentResource::try_new(ftl_string).expect("Could not parse an FTL string.");
19-
let mut bundle = FluentBundle::new(&["x-testing"]);
19+
let mut bundle = FluentBundle::default();
2020
bundle
2121
.add_resource(res)
2222
.expect("Failed to add FTL resources to the bundle.");

fluent-bundle/examples/simple-app.rs

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020
use fluent_bundle::{FluentBundle, FluentResource, FluentValue};
2121
use fluent_locale::{negotiate_languages, NegotiationStrategy};
2222
use std::collections::HashMap;
23+
use std::convert::TryFrom;
2324
use std::env;
2425
use std::fs;
2526
use std::fs::File;
2627
use std::io;
2728
use std::io::prelude::*;
2829
use std::str::FromStr;
30+
use unic_langid::LanguageIdentifier;
2931

3032
/// We need a generic file read helper function to
3133
/// read the localization resource file.
@@ -45,7 +47,7 @@ fn read_file(path: &str) -> Result<String, io::Error> {
4547
///
4648
/// It is expected that every directory inside it
4749
/// has a name that is a valid BCP47 language tag.
48-
fn get_available_locales() -> Result<Vec<String>, io::Error> {
50+
fn get_available_locales() -> Result<Vec<LanguageIdentifier>, io::Error> {
4951
let mut locales = vec![];
5052

5153
let res_dir = fs::read_dir("./fluent-bundle/examples/resources/")?;
@@ -55,7 +57,8 @@ fn get_available_locales() -> Result<Vec<String>, io::Error> {
5557
if path.is_dir() {
5658
if let Some(name) = path.file_name() {
5759
if let Some(name) = name.to_str() {
58-
locales.push(String::from(name));
60+
let langid = LanguageIdentifier::try_from(name).expect("Parsing failed.");
61+
locales.push(langid);
5962
}
6063
}
6164
}
@@ -64,27 +67,6 @@ fn get_available_locales() -> Result<Vec<String>, io::Error> {
6467
return Ok(locales);
6568
}
6669

67-
/// This function negotiates the locales between available
68-
/// and requested by the user.
69-
///
70-
/// It uses `fluent-locale` library but one could
71-
/// use any other that will resolve the list of
72-
/// available locales based on the list of
73-
/// requested locales.
74-
fn get_app_locales(requested: &[&str]) -> Result<Vec<String>, io::Error> {
75-
let available = get_available_locales()?;
76-
let resolved_locales = negotiate_languages(
77-
requested,
78-
&available,
79-
Some("en-US"),
80-
&NegotiationStrategy::Filtering,
81-
);
82-
return Ok(resolved_locales
83-
.into_iter()
84-
.map(|s| String::from(s))
85-
.collect());
86-
}
87-
8870
static L10N_RESOURCES: &[&str] = &["simple.ftl"];
8971

9072
fn main() {
@@ -94,24 +76,34 @@ fn main() {
9476
// 3. If the argument length is more than 1,
9577
// take the second argument as a comma-separated
9678
// list of requested locales.
97-
//
98-
// Otherwise, take ["en-US"] as the default.
99-
let requested = args
100-
.get(2)
101-
.map_or(vec!["en-US"], |arg| arg.split(",").collect());
79+
let requested = args.get(2).map_or(vec![], |arg| {
80+
arg.split(",")
81+
.map(|s| LanguageIdentifier::try_from(s).expect("Parsing locale failed."))
82+
.collect()
83+
});
10284

10385
// 4. Negotiate it against the available ones
104-
let locales = get_app_locales(&requested).expect("Failed to retrieve available locales");
86+
let default_locale = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
87+
let available = get_available_locales().expect("Retrieving available locales failed.");
88+
let resolved_locales = negotiate_languages(
89+
&requested,
90+
&available,
91+
Some(&default_locale),
92+
NegotiationStrategy::Filtering,
93+
);
94+
let current_locale = resolved_locales
95+
.get(0)
96+
.expect("At least one locale should match.");
10597

10698
// 5. Create a new Fluent FluentBundle using the
10799
// resolved locales.
108-
let mut bundle = FluentBundle::new(&locales);
100+
let mut bundle = FluentBundle::new(resolved_locales.clone());
109101

110102
// 6. Load the localization resource
111103
for path in L10N_RESOURCES {
112104
let full_path = format!(
113105
"./fluent-bundle/examples/resources/{locale}/{path}",
114-
locale = locales[0],
106+
locale = current_locale,
115107
path = path
116108
);
117109
let source = read_file(&full_path).expect("Failed to read file.");

fluent-bundle/src/bundle.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
use std::borrow::Borrow;
88
use std::borrow::Cow;
99
use std::collections::hash_map::{Entry as HashEntry, HashMap};
10+
use std::convert::TryFrom;
11+
use std::default::Default;
1012

1113
use fluent_locale::{negotiate_languages, NegotiationStrategy};
1214
use fluent_syntax::ast;
1315
use intl_pluralrules::{IntlPluralRules, PluralRuleType};
16+
use unic_langid::LanguageIdentifier;
1417

1518
use crate::entry::Entry;
1619
use crate::entry::GetEntry;
@@ -33,12 +36,15 @@ pub struct Message<'m> {
3336
/// ```
3437
/// use fluent_bundle::{FluentBundle, FluentResource, FluentValue};
3538
/// use std::collections::HashMap;
39+
/// use std::convert::TryFrom;
40+
/// use unic_langid::LanguageIdentifier;
3641
///
3742
/// let ftl_string = String::from("intro = Welcome, { $name }.");
3843
/// let resource = FluentResource::try_new(ftl_string)
3944
/// .expect("Could not parse an FTL string.");
4045
///
41-
/// let mut bundle = FluentBundle::new(&["en-US"]);
46+
/// let langid_en = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
47+
/// let mut bundle = FluentBundle::new(&[langid_en]);
4248
/// bundle.add_resource(&resource)
4349
/// .expect("Failed to add FTL resources to the bundle.");
4450
///
@@ -86,7 +92,7 @@ pub struct Message<'m> {
8692
/// [`add_resource`]: ./struct.FluentBundle.html#method.add_resource
8793
/// [`Cow<str>`]: http://doc.rust-lang.org/std/borrow/enum.Cow.html
8894
pub struct FluentBundle<R> {
89-
pub locales: Vec<String>,
95+
pub locales: Vec<LanguageIdentifier>,
9096
pub(crate) resources: Vec<R>,
9197
pub(crate) entries: HashMap<String, Entry>,
9298
pub(crate) plural_rules: IntlPluralRules,
@@ -103,27 +109,33 @@ impl<R> FluentBundle<R> {
103109
/// ```
104110
/// use fluent_bundle::FluentBundle;
105111
/// use fluent_bundle::FluentResource;
112+
/// use std::convert::TryFrom;
113+
/// use unic_langid::LanguageIdentifier;
106114
///
107-
/// let mut bundle: FluentBundle<FluentResource> = FluentBundle::new(&["en-US"]);
115+
/// let langid_en = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
116+
/// let mut bundle: FluentBundle<FluentResource> = FluentBundle::new(&[langid_en]);
108117
/// ```
109118
///
110119
/// # Errors
111120
///
112121
/// This will panic if no formatters can be found for the locales.
113-
pub fn new<S: ToString>(locales: &[S]) -> Self {
122+
pub fn new<'a, L: 'a + Into<LanguageIdentifier> + PartialEq + Clone>(
123+
locales: impl IntoIterator<Item = &'a L>,
124+
) -> Self {
114125
let locales = locales
115-
.iter()
116-
.map(std::string::ToString::to_string)
126+
.into_iter()
127+
.map(|s| s.clone().into())
117128
.collect::<Vec<_>>();
129+
let default_langid = LanguageIdentifier::try_from("en").expect("Parsing failed.");
118130
let pr_locale = negotiate_languages(
119131
&locales,
120-
IntlPluralRules::get_locales(PluralRuleType::CARDINAL),
121-
Some("en"),
122-
&NegotiationStrategy::Lookup,
132+
&IntlPluralRules::get_locales(PluralRuleType::CARDINAL),
133+
Some(&default_langid),
134+
NegotiationStrategy::Lookup,
123135
)[0]
124-
.to_owned();
136+
.clone();
125137

126-
let pr = IntlPluralRules::create(&pr_locale, PluralRuleType::CARDINAL)
138+
let pr = IntlPluralRules::create(pr_locale, PluralRuleType::CARDINAL)
127139
.expect("Failed to initialize PluralRules.");
128140
FluentBundle {
129141
locales,
@@ -149,14 +161,17 @@ impl<R> FluentBundle<R> {
149161
///
150162
/// ```
151163
/// use fluent_bundle::{FluentBundle, FluentResource};
164+
/// use std::convert::TryFrom;
165+
/// use unic_langid::LanguageIdentifier;
152166
///
153167
/// let ftl_string = String::from("
154168
/// hello = Hi!
155169
/// goodbye = Bye!
156170
/// ");
157171
/// let resource = FluentResource::try_new(ftl_string)
158172
/// .expect("Could not parse an FTL string.");
159-
/// let mut bundle = FluentBundle::new(&["en-US"]);
173+
/// let langid_en = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
174+
/// let mut bundle = FluentBundle::new(&[langid_en]);
160175
/// bundle.add_resource(resource)
161176
/// .expect("Failed to add FTL resources to the bundle.");
162177
/// assert_eq!(true, bundle.has_message("hello"));
@@ -230,11 +245,14 @@ impl<R> FluentBundle<R> {
230245
///
231246
/// ```
232247
/// use fluent_bundle::{FluentBundle, FluentResource};
248+
/// use std::convert::TryFrom;
249+
/// use unic_langid::LanguageIdentifier;
233250
///
234251
/// let ftl_string = String::from("hello = Hi!");
235252
/// let resource = FluentResource::try_new(ftl_string)
236253
/// .expect("Failed to parse an FTL string.");
237-
/// let mut bundle = FluentBundle::new(&["en-US"]);
254+
/// let langid_en = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
255+
/// let mut bundle = FluentBundle::new(&[langid_en]);
238256
/// bundle.add_resource(&resource)
239257
/// .expect("Failed to add FTL resources to the bundle.");
240258
/// assert_eq!(true, bundle.has_message("hello"));
@@ -262,7 +280,7 @@ impl<R> FluentBundle<R> {
262280
for attr in message.attributes.iter() {
263281
attributes.insert(attr.id.name, &attr.value);
264282
}
265-
return Some(Message { value, attributes });
283+
Some(Message { value, attributes })
266284
}
267285

268286
pub fn format_pattern<'bundle>(
@@ -295,11 +313,14 @@ impl<R> FluentBundle<R> {
295313
///
296314
/// ```
297315
/// use fluent_bundle::{FluentBundle, FluentResource, FluentValue};
316+
/// use std::convert::TryFrom;
317+
/// use unic_langid::LanguageIdentifier;
298318
///
299319
/// let ftl_string = String::from("length = { STRLEN(\"12345\") }");
300320
/// let resource = FluentResource::try_new(ftl_string)
301321
/// .expect("Could not parse an FTL string.");
302-
/// let mut bundle = FluentBundle::new(&["en-US"]);
322+
/// let langid_en = LanguageIdentifier::try_from("en-US").expect("Parsing failed.");
323+
/// let mut bundle = FluentBundle::new(&[langid_en]);
303324
/// bundle.add_resource(&resource)
304325
/// .expect("Failed to add FTL resources to the bundle.");
305326
///
@@ -335,3 +356,20 @@ impl<R> FluentBundle<R> {
335356
}
336357
}
337358
}
359+
360+
impl<R> Default for FluentBundle<R> {
361+
fn default() -> Self {
362+
let pr_langid = LanguageIdentifier::try_from("en").expect("Parsing failed.");
363+
let langid = LanguageIdentifier::new();
364+
365+
let pr = IntlPluralRules::create(pr_langid, PluralRuleType::CARDINAL)
366+
.expect("Failed to initialize PluralRules.");
367+
FluentBundle {
368+
plural_rules: pr,
369+
locales: vec![langid],
370+
resources: vec![],
371+
entries: Default::default(),
372+
use_isolating: false,
373+
}
374+
}
375+
}

0 commit comments

Comments
 (0)