simple_locale/
lib.rs

1/*!
2An interface to all manner of locale-related information.
3
4This crate provides a higher-level interface to a number of locale-related
5sources, in three areas:
6
71. Locale-related codes/identifiers and any standards-based information
8   concerning them. For example, ISO-396 language identifiers, or ISO-3166
9   country identifiers. These are under the module
10   [`simple_locale::codes`](codes/index.html).
111. Locale settings, usually accessed via POSIX (see
12   [ISO/IEC 15897](https://www.iso.org/standard/50707.html) operating system
13   functions. These are under the module
14   [`simple_locale::settings`](settings/index.html).
151. A [`Locale`](locale/enum.Locale.html) enumeration, and a
16   [`LocaleString`](string/struct.LocaleString.html) structure are provided
17   that may be used to parse and construct locale identifiers in
18   a standards-conformant manner.
19
20This crate uses bindgen for the creation of operating system bindings to the
21`langinfo`, `localcharset`, `locale`, and `xlocale` headers. Another
22crate () does something similar, however...
23
24## Example - Codes
25
26The following example demonstrates some of the components of the crate, at
27least some reasonable use cases.
28
291. Construct a _strict_ locale string where identifiers are checked against
30   known standard codes where possible.
311. Lookup the ISO-3166 data for the country (in the
32   [`CountryInfo`](codes/country/struct.CountryInfo.html) struct) identified
33   by the ISO-3166, part 2, 3-character identifier.
341. The data fromn the last call contains one or more regions (in the
35   [`RegionInfo`](/codes/region/struct.RegionInfo.html) struct), determine
36   the countries name from the `country_code`.
371. Now we have the country name we can lookup the details of the currencies
38   (in, the [`CurrencyInfo`](CurrencyInfo) struct).
39
40```
41use simple_locale::LocaleString;
42use simple_locale::codes::{country, currency, region};
43
44let locale = LocaleString::new_strict("en".to_string())
45    .with_territory("US".to_string())
46    .with_code_set("UTF-8".to_string())
47    .with_modifier("collation=pinyin;currency=CNY".to_string());
48println!("{}", locale);
49
50let mexico = country::lookup("MEX").unwrap();
51println!("{:?}", mexico);
52
53let mexico_region = region::lookup(mexico.country_code).unwrap();
54println!("{:?}", mexico_region);
55
56let currencies = currency::currencies_for_country_name(mexico_region.name.as_str());
57println!("{:?}", currencies);
58```
59
60## Example - Settings
61
62In the following example we have a naïve implementation of a currency formatter.
63To format a US dollar amount correctly we first set the current locale for the
64`Currency` [`Category`](settings/locale/enum.Category.html) and then call the
65[`get_currency_format`](settings/currency/fn.get_currency_format.html). From this we use
66only the simplest of the formatting options to display our currency amount.
67
68```
69use std::str::FromStr;
70use simple_locale::{Locale, LocaleString};
71use simple_locale::settings::locale::{Category, set_locale};
72use simple_locale::settings::currency::get_currency_format;
73
74let amount: f64 = 5.909;
75let en_us = LocaleString::from_str("en_US.UTF-8").unwrap();
76
77if set_locale(&Locale::String(en_us), &Category::Currency) {
78    let format = get_currency_format();
79    let local = format.local_format.unwrap();
80    println!(
81        "{2}{0}{3}{1:.4$}",
82        amount.trunc(),
83        amount.fract(),
84        local.currency_symbol,
85        format.number_format.decimal_separator,
86        local.decimal_precision
87    );
88}
89
90```
91## FFI Bindings
92
93As mentioned above, this crate depends on FFI bindings to POSIX locale
94functions, and there are O/S differences that make this a pain. The script
95[`create-bindings.sh`](https://github.com/johnstonskj/simple-locale/blob/master/create-bindings.sh)
96is used to generate these bindings (using cargo bindgen) in such a way that
97different O/S bindings can be built effectively.
98
99## JSON Data Files
100
101The script [`create-data-modules`](https://github.com/johnstonskj/simple-locale/blob/master/create-data-modules.sh)
102on the other hand is used to process files downloaded, or scraped, from
103standards web sites to create data used by the library. This data is generated
104as JSON files in the `src/codes/data` folder and read as a part of the
105build for `codes` modules using the Rust `include!` macro.
106
107Currently data is generated for the following standards:
108
109* ISO 639 _Codes for the representation of names of languages_; Parts 1-4,
110  2-character and 3-character codes supported.
111* ISO 3166 _Codes for the representation of names of countries and their
112  subdivisions_; Part 1, 2-character codes, only.
113* ISO 4217 _Codes for the representation of currencies_; alphabetic and
114  numeric codes supported.
115* ISO 15924 _Codes for the representation of names of scripts_; alphabetic
116  and numeric codes supported.
117
118Each folder under `src-data` represents a single standard, which may
119generate one or more data sets. Each directory will contain a Python
120script, `generate.py` which is called by the top-level script to create
121the JSON in the correct location. Each should also contain a README
122that includes attribution for any data retrieved to make this possible.
123
124*/
125
126#[macro_use]
127extern crate lazy_static;
128#[macro_use]
129extern crate log;
130extern crate regex;
131
132// ------------------------------------------------------------------------------------------------
133// Public Types
134// ------------------------------------------------------------------------------------------------
135
136/// Common error type for functions in this crate.
137#[derive(Debug)]
138pub enum LocaleError {
139    /// The provided locale string was badly formatted
140    InvalidLocaleString,
141    /// The provided locale was unknown
142    UnknownLocale,
143    /// Locale category not set/or supported
144    UnsetCategory,
145    /// Operating system could not set the specified locale
146    OSError,
147    /// The operation you tried to perform was not supported.
148    Unsupported,
149}
150
151/// Common result type for functions in this crate.
152pub type LocaleResult<T> = Result<T, LocaleError>;
153
154// ------------------------------------------------------------------------------------------------
155// Public Modules
156// ------------------------------------------------------------------------------------------------
157
158pub mod codes;
159
160pub mod string;
161pub use string::LocaleString;
162
163pub mod locale;
164pub use locale::Locale;
165
166pub mod settings;
167
168// ------------------------------------------------------------------------------------------------
169// Internal Modules
170// ------------------------------------------------------------------------------------------------
171
172mod ffi;