-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to get language prefs for categories #155
base: v2
Are you sure you want to change the base?
Conversation
Oh, duh. I would have to implement this for the other OS targets as well if I want to have it be exposed to consumers of the library. It seems like Windows has a similar interface for these If I'm reading the documentation correctly. I'll mark this as a draft and work on adding support there. |
@cjohnson19 Thanks for the PR, this is great! Not sure if you're ready for feedback yet, but I think it would be best to change / replace the existing I had in mind something like this: #[non_exhaustive]
pub struct LanguagePrefs {
// maybe not `pub`, and have getters returning `impl Iterator<Item = Language>`?
pub monetary: Vec<Language>,
pub numeric: Vec<Language>,
pub time: Vec<Language>,
pub message: Vec<Language>,
// ...
}
// Maybe named `lang_prefs` or `localization_info`?
pub fn lang_prefs() -> Result<LanguagePrefs> {
todo!()
} For platforms without the lang category support, I think it should set each category to the "main language preferences" (I'm also okay with deferring Windows edit --and other operating systems-- support to a later PR, and using fallback behavior). I'm not fully sure my idea is the design to commit to yet, though - so I'd love to hear if you have other ideas. I think the An alternative idea I have is #[non_exhaustive]
pub enum LocalePreference {
Any(Language, Country),
Message(Language, Country),
Numeric(Language, Country),
Time(Language, Country),
}
// or
pub struct LocalePreference {
// would be `Any`, `Message`, `Numeric`, `Time`, etc.
kind: LocalePreferenceKind,
language: Language,
country: Country,
}
pub fn locale() -> Result<impl Iterator<Item = LocalePreference>> {
todo!()
} Apologies for not writing all my ideas in the original issue, and keeping it in my head until now. Thoughts? |
No, thank you for the guidance! Your approach makes a lot more sense! Your approach of creating a new structure to return looks nice to me. When it comes to providing these categories in the language response, should we override categories with the precedence that is defined in POSIX or should we return them literally? For example, if a user's locale setup is:
Should we return the My gut tells me we handle the precedence, but I can see how some may find that confusing. |
Yeah, looking on it again, I think that's probably the easiest for consumers.
I think following the docs, and override returning |
92b94ad
to
8e43f76
Compare
The `langs` function, `lang_prefs` now, tries to get the user's preferences for each locale category defined within the GNU spec.
8e43f76
to
1e6b3f9
Compare
Sorry for all the failed tests! Don't hesitate to let me know where my code isn't good or is confusing. I couldn't find specific things fix, but felt that I had made some mistakes along the way. |
@@ -2,8 +2,9 @@ use std::{env, ffi::OsString}; | |||
|
|||
use crate::{ | |||
conversions, | |||
language::LanguagePrefs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The language::
prefix can be removed, since LanguagePrefs
is re-exported in the root module.
/// Resulting fields are sorted in order of the user's preference. | ||
/// | ||
/// POSIX locale values and GNU nonstandard categories defined in | ||
/// <https://man7.org/linux/man-pages/man5/locale.5.html>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think probably link to Windows categories here too?
//! return enums, and [`langs()`] that returns an iterator of [`String`]s). The | ||
//! following example shows how to use all of the functions (except those that | ||
//! return [`OsString`]): | ||
//! return enums, and [`lang_prefs()`] that returns an iterator of [`String`]s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be changed to LanguagePrefs
instead of "iterator of [String
]s.
@@ -52,15 +52,17 @@ use std::{ | |||
io::{Error, ErrorKind}, | |||
}; | |||
|
|||
use crate::{Arch, DesktopEnv, Platform, Result}; | |||
use crate::{ | |||
language::LanguagePrefs, Arch, DesktopEnv, Language, Platform, Result, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here also, can get rid of language::
in path
Error::new(kind, e) | ||
}) | ||
fn unix_lang() -> Result<LanguagePrefs> { | ||
let get_env_var = |var: &str| match env::var(var) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Rust method naming usually 'get' is implicit. So I think, env_var
is a more "idiomatic" name for the closure.
/// Determines the interpretation of byte sequences as characters (e.g., | ||
/// single versus multibyte characters), character classifications (e.g., | ||
/// alphabetic or digit), and the behavior of character classes. | ||
pub ctype: Vec<Language>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is the name used by the environment variables, but I think something like char_classes
is more descriptive / a better name.
/// Determines collation rules used for sorting and regular expressions, | ||
/// including character equivalence classes and multicharacter collating | ||
/// elements. | ||
pub collate: Vec<Language>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe it should be collation
instead of collate
pub struct LanguagePrefs { | ||
/// Determines general user language preference, should be used in | ||
/// situations which are not encompassed by other [`LanguagePrefs`]. | ||
pub lang: Vec<Language>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be missing something, but I think "messages" generally could be used as the "catch-all", so I'm not sure this field is needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, actually I'm thinking about this maybe being something that's needed. Since there's two possibilities:
- Remove
lang
- each other field, appends what would have been inlang
if theLanguage
wasn't already contained in theVec
- Rename
lang
tofallback
- each other field is an emptyVec
if it the environment variable isn't set, add methods for getting each language category:
fn collation_langs(&self) -> impl Iterator<Item = Lang> {
// not sure if this compiles, but this idea
self.collate.iter()
.cloned()
.zip(self.fallback.iter().filter(|lang| {
!self.collate.contains(&lang)
}).cloned())
}
I'm leaning towards the second option, since it's less allocations / duplications on the simple/common case
@@ -57,6 +57,20 @@ impl Language { | |||
} | |||
} | |||
|
|||
/// Reads an `ll_CC` formatted string into a [`Language`]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a normal comment (not a doc comment). It also took me a bit to understand what ll_CC
meant (full format would also be "lang_COUNTRY.Encoding
, with lang
being a 2-letter language code, and COUNTRY
being 2-letter country code").
writeln!(f, "LC_MESSAGES=\"{}\"", format_langs(&self.messages))?; | ||
writeln!(f, "LC_MONETARY=\"{}\"", format_langs(&self.monetary))?; | ||
writeln!(f, "LC_NUMERIC=\"{}\"", format_langs(&self.numeric))?; | ||
write!(f, "LC_TIME=\"{}\"", format_langs(&self.time)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the formatting here is probably not what we want (too specific to environment variable names).
This implementation doesn't need to be in this PR, but the examples should use the Display
implementation if it exists.
Perhaps something like:
Collation=en/US,de/DE;CharClass=en/US,Messages=en/US,Monetary=en/US;Numeric=en/US,Time=en/US
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to stop mid-review, but checked everything now. I know I made a lot of comments, but I think it's mostly minor things (like using use language::
when exported in root), this is great!
// Languages that have a higher global precedence than their specific | ||
// counterparts | ||
if let Some(l) = &lang { | ||
if l == "C" || l == "POSIX" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the POSIX
"lang" documented anywhere that could be linked here?
@@ -6,14 +6,15 @@ use std::{ | |||
}; | |||
|
|||
use crate::{ | |||
language::{Language, LanguagePrefs}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to remove language::
path prefix here too
Adds a new
lang_category
function which accepts the POSIX standard locale category values. Each value is checked in priority order as:LC_ALL
LC_xxx
LANG
Closes #145