diff --git a/Cargo.lock b/Cargo.lock index c2ecdce..3a8336e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cargo-i18n" -version = "0.1.9" +version = "0.1.10" dependencies = [ "anyhow", "clap", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "i18n-build" -version = "0.4.0" +version = "0.4.1" dependencies = [ "anyhow", "gettext", @@ -249,7 +249,7 @@ dependencies = [ [[package]] name = "i18n-embed" -version = "0.5.0" +version = "0.6.0" dependencies = [ "doc-comment", "fluent-langneg", diff --git a/Cargo.toml b/Cargo.toml index 9f89edc..2d5600c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "cargo-i18n" readme = "README.md" repository = "https://github.com/kellpossible/cargo-i18n" -version = "0.1.9" +version = "0.1.10" [badges] maintenance = { status = "actively-developed" } @@ -16,13 +16,13 @@ maintenance = { status = "actively-developed" } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -i18n-embed = { version = "0.5", path = "./i18n-embed", features = ["desktop-requester"] } +i18n-embed = { version = "0.6", path = "./i18n-embed", features = ["desktop-requester"] } i18n-build = { version = "0.4", path = "./i18n-build", features = ["localize"] } i18n-config = { version = "0.2", path = "./i18n-config" } anyhow = "1.0" gettext = "0.4" tr = { version = "0.1", default-features = false, features = ["gettext"] } -clap = "2.33.0" +clap = "2.33" rust-embed = "5" unic-langid = "0.9" env_logger = "0.7.1" diff --git a/i18n-build/CHANGELOG.md b/i18n-build/CHANGELOG.md index 6fd3809..1ac8769 100644 --- a/i18n-build/CHANGELOG.md +++ b/i18n-build/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog for `i18n-build` +## v0.4.1 + ++ Update to `i18n-embed` version `0.6.0`. + ## v0.4.0 + Update to `i18n-embed` version `0.5.0`. diff --git a/i18n-build/Cargo.toml b/i18n-build/Cargo.toml index f7861b8..edfd40c 100644 --- a/i18n-build/Cargo.toml +++ b/i18n-build/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "i18n-build" readme = "README.md" repository = "https://github.com/kellpossible/cargo-i18n/tree/master/i18n-build" -version = "0.4.0" +version = "0.4.1" [package.metadata.docs.rs] all-features = true @@ -24,7 +24,7 @@ anyhow = "1" thiserror = "1" tr = { version = "0.1", default-features = false, features = ["gettext"] } walkdir = "2" -i18n-embed = { version = "0.5", path = "../i18n-embed", features = ["desktop-requester"], optional = true } +i18n-embed = { version = "0.6", path = "../i18n-embed", features = ["desktop-requester"], optional = true } i18n-config = { version = "0.2", path = "../i18n-config" } gettext = { version = "0.4", optional = true } log = "0.4" diff --git a/i18n-embed/CHANGELOG.md b/i18n-embed/CHANGELOG.md index 2857c90..f785f07 100644 --- a/i18n-embed/CHANGELOG.md +++ b/i18n-embed/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog for `i18n-embed` +## v0.6.0 + ++ Changed the argument for `LanguageRequester::add_listener()` to use a `std::rc::Weak` instead of `std::rc::Rc` to make it more obvious that it is the caller's responsibility to hold on to the `Rc` in order to maintain the reference. ++ Fixed typo in `LanguageRequester::set_language_override()`. + ## v0.5.0 + Refactored `I18nEmbedError::Multiple(Box>)` to `I18nEmbedError::Multiple(Vec)`, removing the useless box (and complaining Clippy lint). diff --git a/i18n-embed/Cargo.toml b/i18n-embed/Cargo.toml index d1bdd0a..d115d3e 100644 --- a/i18n-embed/Cargo.toml +++ b/i18n-embed/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" name = "i18n-embed" readme = "README.md" repository = "https://github.com/kellpossible/cargo-i18n/tree/master/i18n-embed" -version = "0.5.0" +version = "0.6.0" [package.metadata.docs.rs] all-features = true diff --git a/i18n-embed/src/lib.rs b/i18n-embed/src/lib.rs index 78915a7..8444d62 100644 --- a/i18n-embed/src/lib.rs +++ b/i18n-embed/src/lib.rs @@ -107,7 +107,7 @@ //! let localizer_rc: Rc = Rc::new(localizer); //! //! let mut language_requester = DesktopLanguageRequester::new(); -//! language_requester.add_listener(&localizer_rc); +//! language_requester.add_listener(Rc::downgrade(&localizer_rc)); //! //! // Manually check the currently requested system language, //! // and update the listeners. When the system language changes, @@ -239,7 +239,10 @@ extern crate i18n_embed_impl; pub use i18n_embed_impl::*; use std::borrow::Cow; -use std::rc::{Rc, Weak}; +use std::{ + collections::{HashMap, HashSet}, + rc::Weak, +}; use fluent_langneg::{negotiate_languages, NegotiationStrategy}; use log::{debug, error, info}; @@ -340,7 +343,7 @@ impl<'a> LanguageRequesterImpl<'a> { /// Set an override for the requested language which is used when the /// [LanguageRequesterImpl#poll()](LanguageRequester#poll()) method /// is called. If `None`, then no override is used. - fn set_languge_override( + fn set_language_override( &mut self, language_override: Option, ) -> Result<(), I18nEmbedError> { @@ -348,8 +351,8 @@ impl<'a> LanguageRequesterImpl<'a> { Ok(()) } - fn add_listener(&mut self, localizer: &Rc>) { - self.listeners.push(Rc::downgrade(localizer)); + fn add_listener(&mut self, localizer: Weak>) { + self.listeners.push(localizer); } /// With the provided `requested_languages` call @@ -387,7 +390,7 @@ impl<'a> LanguageRequesterImpl<'a> { /// With the provided `requested_languages` call /// [Localizer#select()](Localizer#select()) on each of the /// listeners. The `requested_languages` may be ignored if - /// [#set_languge_override()](#set_languge_override()) has been + /// [#set_language_override()](#set_language_override()) has been /// set. pub fn poll( &mut self, @@ -403,6 +406,36 @@ impl<'a> LanguageRequesterImpl<'a> { self.poll_without_override(languages) } + + /// The languages reported to be available in the + /// listener [Localizer](Localizer)s. + fn available_languages(&self) -> Result, I18nEmbedError> { + let mut available_languages = HashSet::new(); + for weak_listener in &self.listeners { + if let Some(localizer) = weak_listener.upgrade() { + localizer + .available_languages()? + .iter() + .for_each(|language| { + available_languages.insert(language.clone()); + }) + } + } + + Ok(available_languages.into_iter().collect()) + } + + fn current_languages(&self) -> HashMap<&'static str, unic_langid::LanguageIdentifier> { + let mut current_languages = HashMap::new(); + for weak_listener in &self.listeners { + if let Some(localizer) = weak_listener.upgrade() { + let loader = localizer.language_loader(); + current_languages.insert(loader.domain(), loader.current_language()); + } + } + + current_languages + } } /// A trait used by [I18nEmbed](I18nEmbed) to ascertain which @@ -416,31 +449,25 @@ pub trait LanguageRequester<'a> { /// If you haven't already selected a language for the localizer /// you are adding here, you may want to manually call /// [#poll()](#poll()) after adding the listener/s. - fn add_listener(&mut self, localizer: &Rc>); + fn add_listener(&mut self, localizer: Weak>); /// Poll the system's currently selected language, and call /// [Localizer#select()](Localizer#select()) on each of the /// listeners. fn poll(&mut self) -> Result<(), I18nEmbedError>; /// Override the languages fed to the [Localizer](Localizer) listeners during /// a [#poll()](#poll()). Set this as `None` to disable the override. - fn set_languge_override( + fn set_language_override( &mut self, language_override: Option, ) -> Result<(), I18nEmbedError>; - /// Get the language last selected for the [LanguageLoader](LanguageLoader) - /// by this [LanguageRequester](LanguageRequester). - // fn currently_selected_language(&self, language_loader: &'a dyn LanguageLoader) -> &Option; - // fn override_request(&self, language_id: unic_langid::LanguageIdentifier); - // fn reset_override_request(&self); - // /// Attach a listener to the system this requester is mediating - // /// for, to listen for changes, and trigger a language update if - // /// required. - // fn attach_system_listener(&self) -> Result<(), Box>; - // /// Detach the listener which was attached using - // /// [attach_change_listener()](#attach_change_lister()). - // fn detatch_system_listener(&self) -> Result<(), Box>; /// The currently requested languages. fn requested_languages(&self) -> Vec; + /// The languages reported to be available in the + /// listener [Localizer](Localizer)s. + fn available_languages(&self) -> Result, I18nEmbedError>; + /// The languages currently loaded, keyed by the + /// [LanguageLoader::domain()](LanguageLoader::domain()). + fn current_languages(&self) -> HashMap<&'static str, unic_langid::LanguageIdentifier>; } /// Select the most suitable language currently requested by the @@ -655,20 +682,28 @@ impl<'a> LanguageRequester<'a> for DesktopLanguageRequester<'a> { Self::requested_languages() } - fn add_listener(&mut self, localizer: &Rc>) { + fn add_listener(&mut self, localizer: Weak>) { self.implementation.add_listener(localizer) } - fn set_languge_override( + fn set_language_override( &mut self, language_override: Option, ) -> Result<(), I18nEmbedError> { - self.implementation.set_languge_override(language_override) + self.implementation.set_language_override(language_override) } fn poll(&mut self) -> Result<(), I18nEmbedError> { self.implementation.poll(self.requested_languages()) } + + fn available_languages(&self) -> Result, I18nEmbedError> { + self.implementation.available_languages() + } + + fn current_languages(&self) -> HashMap<&'static str, unic_langid::LanguageIdentifier> { + self.implementation.current_languages() + } } #[cfg(feature = "desktop-requester")] @@ -747,7 +782,7 @@ impl<'a> LanguageRequester<'a> for WebLanguageRequester<'a> { Self::requested_languages() } - fn add_listener(&mut self, localizer: &Rc>) { + fn add_listener(&mut self, localizer: Weak>) { self.implementation.add_listener(localizer) } @@ -755,11 +790,19 @@ impl<'a> LanguageRequester<'a> for WebLanguageRequester<'a> { self.implementation.poll(self.requested_languages()) } - fn set_languge_override( + fn set_language_override( &mut self, language_override: Option, ) -> Result<(), I18nEmbedError> { - self.implementation.set_languge_override(language_override) + self.implementation.set_language_override(language_override) + } + + fn available_languages(&self) -> Result, I18nEmbedError> { + self.implementation.available_languages() + } + + fn current_languages(&self) -> HashMap<&'static str, unic_langid::LanguageIdentifier> { + self.implementation.current_languages() } } diff --git a/src/main.rs b/src/main.rs index dd92049..ef90b6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,8 +81,8 @@ fn main() -> Result<()> { let cargo_i18n_localizer_rc: Rc = Rc::new(cargo_i18n_localizer); let i18n_build_localizer_rc = Rc::new(i18n_build::localizer()) as Rc>; - language_requester.add_listener(&cargo_i18n_localizer_rc); - language_requester.add_listener(&i18n_build_localizer_rc); + language_requester.add_listener(Rc::downgrade(&cargo_i18n_localizer_rc)); + language_requester.add_listener(Rc::downgrade(&i18n_build_localizer_rc)); language_requester.poll()?; let src_locale = LANGUAGE_LOADER.src_locale().to_string(); @@ -150,7 +150,7 @@ fn main() -> Result<()> { .expect("expected a default language to be present"); let li: LanguageIdentifier = language.parse()?; - language_requester.set_languge_override(Some(li))?; + language_requester.set_language_override(Some(li))?; language_requester.poll()?; let path = i18n_matches