locale_config-0.3.0/.gitignore010064400017500001750000000000221306360274600145100ustar0000000000000000target Cargo.lock locale_config-0.3.0/Cargo.toml.orig010064400017500001750000000015501352756102300154130ustar0000000000000000[package] name = "locale_config" version = "0.3.0" description = """ Maintains locale preferences for process and thread and initialises them by inspecting the system for user preference. """ authors = [ "Jan Hudec ", ] license = "MIT" documentation = "https://docs.rs/locale_config/" repository = "https://github.com/rust-locale/locale_config/" readme = "README.md" keywords = ["i18n"] categories = ["os"] exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"] [package.metadata.release] upload-doc = true [badges] travis-ci = { repository = "rust-locale/locale_config" } appveyor = { repository = "rust-locale/locale_config" } [dependencies] lazy_static = "1" regex = "1" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winnls"] } [target.'cfg(target_os = "macos")'.dependencies] objc = "^0.2" objc-foundation = "^0.1" locale_config-0.3.0/Cargo.toml0000644000000027020000000000000116560ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "locale_config" version = "0.3.0" authors = ["Jan Hudec "] exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"] description = "Maintains locale preferences for process and thread and initialises them by\ninspecting the system for user preference.\n" documentation = "https://docs.rs/locale_config/" readme = "README.md" keywords = ["i18n"] categories = ["os"] license = "MIT" repository = "https://github.com/rust-locale/locale_config/" [package.metadata.release] upload-doc = true [dependencies.lazy_static] version = "1" [dependencies.regex] version = "1" [target."cfg(target_os = \"macos\")".dependencies.objc] version = "^0.2" [target."cfg(target_os = \"macos\")".dependencies.objc-foundation] version = "^0.1" [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["winnls"] [badges.appveyor] repository = "rust-locale/locale_config" [badges.travis-ci] repository = "rust-locale/locale_config" locale_config-0.3.0/LICENSE010064400017500001750000000024721352755612100135400ustar0000000000000000The MIT License (MIT) Copyright (c) 2016–2019 Jan Hudec Copyright (c) 2016 A.J. Gardner Copyright (c) 2019, Bastien Orivel Copyright (c) 2019, Igor Gnatenko Copyright (c) 2019, Sophie Tauchert <999eagle@999eagle.moe> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. locale_config-0.3.0/README.md010064400017500001750000000106171352755630200140130ustar0000000000000000[![TravisCI Build Status](https://travis-ci.org/rust-locale/locale_config.svg?branch=master)](https://travis-ci.org/rust-locale/locale_config) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/13100wtqs80tyink/branch/master?svg=true)](https://ci.appveyor.com/project/jan-hudec/locale-config/branch/master) [![Crates.io Version](https://img.shields.io/crates/v/locale_config.svg)](https://crates.io/crates/locale_config) [![Docs.rs](https://docs.rs/locale_config/badge.svg)](https://docs.rs/locale_config/) # `locale_config` Remembers locale configuration per-thread and per-process and initializes the values by inspecting the system for user preferences. ## Installation You can depend on this library by adding `locale_config` to your Cargo dependencies: ```toml [dependencies] locale_config = "*" ``` Usually it is not recommended to depend on `*`, but in this case it is important that incompatible version requirements don't cause multiple versions to be pulled in the final binary, so I do recommend it here and promise I will maintain good compatibility. Just please don't add traits to the types defined here to avoid conflicts with potential future methods. ## Using Usually you want to use this indirectly via a localization crate like `locale`. However if you need to work with the identifier itself, or you need to override it, use ```rust Locale::current() ``` to find what you should be using at any given point in the application, ```rust Locale::set_current() ``` to override it for current thread and ```rust Locale::set_global_default() ``` to override it for new threads. In case you need to access the initial value, you'll find it under ```rust Locale::user_default() ``` The value may contain language tags specific for various localization aspects, called categories, and fallbacks. The `Locale::tags_for` method will take care of selecting relevant tags for you. For preferred language of translations, use ```rust Locale::current().tags_for("messages") ``` For formatting, use categories `"numeric"` for numbers, `"time"` for date and time and `"monetary"` for money amounts. And use `"collate"` for collation. Note that this crate does not itself provide any translation, formatting nor collation functionality. Formatting and collation will be provided by `locale` crate, translation has multiple available implementations. See full documentation on [![Docs.rs](https://docs.rs/locale_config/badge.svg)](https://docs.rs/locale_config/) or [github](https://rust-locale.github.io/locale_config/locale_config/). ## Supported systems * **Unix:** Using the POSIX standard environment variables `LANG`, `LC_*` and `LANGUAGES`. The variables are recognized on all systems and take precedence on most of them. * **Windows:** Vista and newer - Uses API available from Vista and Server 2008 only. - The `GetUserPreferredUILanguages` is only available for desktop, but not store applications. Store applications should have equivalent functionality, but I didn't try accessing it from Rust yet. - Customization to individual locale elements done in “Regional and Language options” (digits, calendar, decimal and thousand separator etc.) are not detected (yet). - Not well tested. * **OS X:** Reads setting from `NSLocale`, can be overridden by setting the Unix environment variables. * **CGI:** The `HTTP_ACCEPT_LANGUAGE` environment variable is used if detected. Hopefully it is specific enough to the CGI environment that it can be used whenever detected. ## Changelog ### 0.3.0 * Support OS X `NSLocale`. Thanks Sophie Tauchert (@999eagle). ### 0.2.3 * Try support getting locale in emscripten targets in browser. Unfortunately the emscripten targets seem to have broken in cross meanwhile, so they are not being tested. * Update to winapi 0.3. * Update ro regex 1.0. ### 0.2.2 * Update dependencies: regex 0.2. ### 0.2.1 * Interpret some overrides that can be set on Windows in Region and Language dialog, namely: group, decimal and list separators, first day of week, 12/24-hour time, measurement system, (decimal) number system, to an extent negative monetary value format (only whether to use parenthesized format or not) and to an extent date format (if ISO-8601 variant is selected). ### 0.2.0 * Changed error handling to proper error type. ### 0.1.1 * Added basic Windows support. ### 0.1.0 * Initial version, with Unix and CGI support. locale_config-0.3.0/examples/show-user-locale.rs010064400017500001750000000001521306360274600201010ustar0000000000000000extern crate locale_config; pub fn main() { println!("{}", locale_config::Locale::user_default()); } locale_config-0.3.0/src/cgi.rs010064400017500001750000000004161306360274600144260ustar0000000000000000//! Inspect CGI environment variables for locale configuration use std::env; use super::{Locale}; pub fn system_locale() -> Option { if let Ok(al) = env::var("HTTP_ACCEPT_LANGUAGE") { Locale::new(al.as_ref()).ok() } else { None } } locale_config-0.3.0/src/emscripten.rs010064400017500001750000000017041315460353700160360ustar0000000000000000use std::ffi::CStr; use std::os::raw::c_char; use std::os::raw::c_int; use super::Locale; // Bind some emscripten functions. Copied from webplatform crate. extern "C" { pub fn emscripten_asm_const_int(s: *const c_char, ...) -> c_int; } pub fn system_locale() -> Option { const JS: &'static [u8] = b"\ try { \ return allocate(intArrayFromString(navigator.languages.join(',')), 'i8', ALLOC_STACK); \ } catch(e) {} \ try { \ return allocate(intArrayFromString(navigator.language), 'i8', ALLOC_STACK); \ } catch(e) {} \ try { \ return allocate(intArrayFromString(navigator.userLanguage), 'i8', ALLOC_STACK); \ } catch(e) {} \ return 0;\0"; unsafe { let cptr = emscripten_asm_const_int(&JS[0] as *const _ as *const c_char); return CStr::from_ptr(cptr as *const c_char).to_str().ok() .and_then(|s| Locale::new(s).ok()); } }locale_config-0.3.0/src/lib.rs010064400017500001750000001065101352755464200144420ustar0000000000000000//! Global locale instances and system inspection. //! //! This is an auxiliary crate for i18n solutions that: //! //! - Holds the appropriate default instances of locale. //! - Inspects the system for the initial values. //! //! You don't want to use it directly, but instead use an internationalisation crate like [locale]. //! //! This crate is separate and intentionally minimal so that multiple i18n crates or multiple //! versions of one that get into the application still share the current locale setting. //! //! [locale]: https://crates.io/crates/locale #[macro_use] extern crate lazy_static; extern crate regex; #[cfg(target_os = "macos")] #[macro_use] extern crate objc; use regex::Regex; use std::borrow::{Borrow,Cow}; use std::cell::RefCell; use std::convert::AsRef; use std::fmt; use std::sync::Mutex; // ------------------------------ LANGUAGE RANGE --------------------------------- /// Language and culture identifier. /// /// This object holds a [RFC4647] extended language range. /// /// The internal data may be owned or shared from object with lifetime `'a`. The lifetime can be /// extended using the `into_static()` method, which internally clones the data as needed. /// /// # Syntax /// /// The range is composed of `-`-separated alphanumeric subtags, possibly replaced by `*`s. It /// might be empty. /// /// In agreement with [RFC4647], this object only requires that the tag matches: /// /// ```ebnf /// language_tag = (alpha{1,8} | "*") /// ("-" (alphanum{1,8} | "*"))* /// ``` /// /// The exact interpretation is up to the downstream localization provider, but it expected that /// it will be matched against a normalized [RFC5646] language tag, which has the structure: /// /// ```ebnf /// language_tag = language /// ("-" script)? /// ("-" region)? /// ("-" variant)* /// ("-" extension)* /// ("-" private)? /// /// language = alpha{2,3} ("-" alpha{3}){0,3} /// /// script = aplha{4} /// /// region = alpha{2} /// | digit{3} /// /// variant = alphanum{5,8} /// | digit alphanum{3} /// /// extension = [0-9a-wyz] ("-" alphanum{2,8})+ /// /// private = "x" ("-" alphanum{1,8})+ /// ``` /// /// * `language` is an [ISO639] 2-letter or, where not defined, 3-letter code. A code for /// macro-language might be followed by code of specific dialect. /// * `script` is an [ISO15924] 4-letter code. /// * `region` is either an [ISO3166] 2-letter code or, for areas other than countries, [UN M.49] /// 3-digit numeric code. /// * `variant` is a string indicating variant of the language. /// * `extension` and `private` define additional options. The private part has same structure as /// the Unicode [`-u-` extension][u_ext]. Available options are documented for the facets that /// use them. /// /// The values obtained by inspecting the system are normalized according to those rules. /// /// The content will be case-normalized as recommended in [RFC5646] §2.1.1, namely: /// /// * `language` is written in lowercase, /// * `script` is written with first capital, /// * `country` is written in uppercase and /// * all other subtags are written in lowercase. /// /// When detecting system configuration, additional options that may be generated under the /// [`-u-` extension][u_ext] currently are: /// /// * `cf` — Currency format (`account` for parenthesized negative values, `standard` for minus /// sign). /// * `fw` — First day of week (`mon` to `sun`). /// * `hc` — Hour cycle (`h12` for 1–12, `h23` for 0–23). /// * `ms` — Measurement system (`metric` or `ussystem`). /// * `nu` — Numbering system—only decimal systems are currently used. /// * `va` — Variant when locale is specified in Unix format and the tag after `@` does not /// correspond to any variant defined in [Language subtag registry]. /// /// And under the `-x-` extension, following options are defined: /// /// * `df` — Date format: /// /// * `iso`: Short date should be in ISO format of `yyyy-MM-dd`. /// /// For example `-df-iso`. /// /// * `dm` — Decimal separator for monetary: /// /// Followed by one or more Unicode codepoints in hexadecimal. For example `-dm-002d` means to /// use comma. /// /// * `ds` — Decimal separator for numbers: /// /// Followed by one or more Unicode codepoints in hexadecimal. For example `-ds-002d` means to /// use comma. /// /// * `gm` — Group (thousand) separator for monetary: /// /// Followed by one or more Unicode codepoints in hexadecimal. For example `-dm-00a0` means to /// use non-breaking space. /// /// * `gs` — Group (thousand) separator for numbers: /// /// Followed by one or more Unicode codepoints in hexadecimal. For example `-ds-00a0` means to /// use non-breaking space. /// /// * `ls` — List separator: /// /// Followed by one or more Unicode codepoints in hexadecimal. For example, `-ds-003b` means to /// use a semicolon. /// /// [RFC5646]: https://www.rfc-editor.org/rfc/rfc5646.txt /// [RFC4647]: https://www.rfc-editor.org/rfc/rfc4647.txt /// [ISO639]: https://en.wikipedia.org/wiki/ISO_639 /// [ISO15924]: https://en.wikipedia.org/wiki/ISO_15924 /// [ISO3166]: https://en.wikipedia.org/wiki/ISO_3166 /// [UN M.49]: https://en.wikipedia.org/wiki/UN_M.49 /// [u_ext]: http://www.unicode.org/reports/tr35/#u_Extension /// [Language subtag registry]: https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry #[derive(Clone,Debug,Eq,Hash,PartialEq)] pub struct LanguageRange<'a> { language: Cow<'a, str> } lazy_static! { static ref REGULAR_LANGUAGE_RANGE_REGEX: Regex = Regex::new(r"(?x) ^ (?P (?: [[:alpha:]]{2,3} (?: - [[:alpha:]]{3} ){0,3} | \* )) (?P