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
/*!
An interface to all manner of locale-related information.

This crate provides a higher-level interface to a number of locale-related
sources, in three areas:

1. Locale-related codes/identifiers and any standards-based information
   concerning them. For example, ISO-396 language identifiers, or ISO-3166
   country identifiers. These are under the module
   [`simple_locale::codes`](codes/index.html).
1. Locale settings, usually accessed via POSIX (see
   [ISO/IEC 15897](https://www.iso.org/standard/50707.html) operating system
   functions. These are under the module
   [`simple_locale::settings`](settings/index.html).
1. A [`Locale`](locale/enum.Locale.html) enumeration, and a
   [`LocaleString`](string/struct.LocaleString.html) structure are provided
   that may be used to parse and construct locale identifiers in
   a standards-conformant manner.

This crate uses bindgen for the creation of operating system bindings to the
`langinfo`, `localcharset`, `locale`, and `xlocale` headers. Another
crate () does something similar, however...

## Example - Codes

The following example demonstrates some of the components of the crate, at
least some reasonable use cases.

1. Construct a _strict_ locale string where identifiers are checked against
   known standard codes where possible.
1. Lookup the ISO-3166 data for the country (in the
   [`CountryInfo`](codes/country/struct.CountryInfo.html) struct) identified
   by the ISO-3166, part 2, 3-character identifier.
1. The data fromn the last call contains one or more regions (in the
   [`RegionInfo`](/codes/region/struct.RegionInfo.html) struct), determine
   the countries name from the `country_code`.
1. Now we have the country name we can lookup the details of the currencies
   (in, the [`CurrencyInfo`](CurrencyInfo) struct).

```
use simple_locale::LocaleString;
use simple_locale::codes::{country, currency, region};

let locale = LocaleString::new_strict("en".to_string())
    .with_territory("US".to_string())
    .with_code_set("UTF-8".to_string())
    .with_modifier("collation=pinyin;currency=CNY".to_string());
println!("{}", locale);

let mexico = country::lookup("MEX").unwrap();
println!("{:?}", mexico);

let mexico_region = region::lookup(mexico.country_code).unwrap();
println!("{:?}", mexico_region);

let currencies = currency::currencies_for_country_name(mexico_region.name.as_str());
println!("{:?}", currencies);
```

## Example - Settings

In the following example we have a naïve implementation of a currency formatter.
To format a US dollar amount correctly we first set the current locale for the
`Currency` [`Category`](settings/locale/enum.Category.html) and then call the
[`get_currency_format`](settings/currency/fn.get_currency_format.html). From this we use
only the simplest of the formatting options to display our currency amount.

```
use std::str::FromStr;
use simple_locale::{Locale, LocaleString};
use simple_locale::settings::locale::{Category, set_locale};
use simple_locale::settings::currency::get_currency_format;

let amount: f64 = 5.909;
let en_us = LocaleString::from_str("en_US.UTF-8").unwrap();

if set_locale(&Locale::String(en_us), &Category::Currency) {
    let format = get_currency_format();
    let local = format.local_format.unwrap();
    println!(
        "{2}{0}{3}{1:.4$}",
        amount.trunc(),
        amount.fract(),
        local.currency_symbol,
        format.number_format.decimal_separator,
        local.decimal_precision
    );
}

```
## FFI Bindings

As mentioned above, this crate depends on FFI bindings to POSIX locale
functions, and there are O/S differences that make this a pain. The script
[`create-bindings.sh`](https://github.com/johnstonskj/simple-locale/blob/master/create-bindings.sh)
is used to generate these bindings (using cargo bindgen) in such a way that
different O/S bindings can be built effectively.

## JSON Data Files

The script [`create-data-modules`](https://github.com/johnstonskj/simple-locale/blob/master/create-data-modules.sh)
on the other hand is used to process files downloaded, or scraped, from
standards web sites to create data used by the library. This data is generated
as JSON files in the `src/codes/data` folder and read as a part of the
build for `codes` modules using the Rust `include!` macro.

Currently data is generated for the following standards:

* ISO 639 _Codes for the representation of names of languages_; Parts 1-4,
  2-character and 3-character codes supported.
* ISO 3166 _Codes for the representation of names of countries and their
  subdivisions_; Part 1, 2-character codes, only.
* ISO 4217 _Codes for the representation of currencies_; alphabetic and
  numeric codes supported.
* ISO 15924 _Codes for the representation of names of scripts_; alphabetic
  and numeric codes supported.

Each folder under `src-data` represents a single standard, which may
generate one or more data sets. Each directory will contain a Python
script, `generate.py` which is called by the top-level script to create
the JSON in the correct location. Each should also contain a README
that includes attribution for any data retrieved to make this possible.

*/

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate regex;

// ------------------------------------------------------------------------------------------------
// Public Types
// ------------------------------------------------------------------------------------------------

/// Common error type for functions in this crate.
#[derive(Debug)]
pub enum LocaleError {
    /// The provided locale string was badly formatted
    InvalidLocaleString,
    /// The provided locale was unknown
    UnknownLocale,
    /// Locale category not set/or supported
    UnsetCategory,
    /// Operating system could not set the specified locale
    OSError,
    /// The operation you tried to perform was not supported.
    Unsupported,
}

/// Common result type for functions in this crate.
pub type LocaleResult<T> = Result<T, LocaleError>;

// ------------------------------------------------------------------------------------------------
// Public Modules
// ------------------------------------------------------------------------------------------------

pub mod codes;

pub mod string;
pub use string::LocaleString;

pub mod locale;
pub use locale::Locale;

pub mod settings;

// ------------------------------------------------------------------------------------------------
// Internal Modules
// ------------------------------------------------------------------------------------------------

mod ffi;