translations: Make the code cleaner
This commit is contained in:
		@ -1,4 +1,10 @@
 | 
				
			|||||||
/*! Locale-specific functions. */
 | 
					/*! Locale-specific functions. 
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This file is intended as a library:
 | 
				
			||||||
 | 
					 * it must pass errors upwards
 | 
				
			||||||
 | 
					 * and panicking is allowed only when
 | 
				
			||||||
 | 
					 * this code encounters an internal inconsistency.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::cmp;
 | 
					use std::cmp;
 | 
				
			||||||
use std::ffi::{ CStr, CString };
 | 
					use std::ffi::{ CStr, CString };
 | 
				
			||||||
 | 
				
			|||||||
@ -70,12 +70,12 @@ pub enum Level {
 | 
				
			|||||||
/// Approach 2.
 | 
					/// Approach 2.
 | 
				
			||||||
pub trait Warn {
 | 
					pub trait Warn {
 | 
				
			||||||
    type Value;
 | 
					    type Value;
 | 
				
			||||||
    fn ok_warn(self, msg: &str) -> Option<Self::Value>;
 | 
					    fn or_warn(self, msg: &str) -> Option<Self::Value>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T, E: Error> Warn for Result<T, E> {
 | 
					impl<T, E: Error> Warn for Result<T, E> {
 | 
				
			||||||
    type Value = T;
 | 
					    type Value = T;
 | 
				
			||||||
    fn ok_warn(self, msg: &str) -> Option<T> {
 | 
					    fn or_warn(self, msg: &str) -> Option<T> {
 | 
				
			||||||
        self.map_err(|e| {
 | 
					        self.map_err(|e| {
 | 
				
			||||||
            eprintln!("{}: {}", msg, e);
 | 
					            eprintln!("{}: {}", msg, e);
 | 
				
			||||||
            e
 | 
					            e
 | 
				
			||||||
@ -83,6 +83,16 @@ impl<T, E: Error> Warn for Result<T, E> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> Warn for Option<T> {
 | 
				
			||||||
 | 
					    type Value = T;
 | 
				
			||||||
 | 
					    fn or_warn(self, msg: &str) -> Option<T> {
 | 
				
			||||||
 | 
					        self.or_else(|| {
 | 
				
			||||||
 | 
					            eprintln!("{}", msg);
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A mutable handler for text warnings.
 | 
					/// A mutable handler for text warnings.
 | 
				
			||||||
/// Approach 3.
 | 
					/// Approach 3.
 | 
				
			||||||
pub trait WarningHandler {
 | 
					pub trait WarningHandler {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										140
									
								
								src/popover.rs
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								src/popover.rs
									
									
									
									
									
								
							@ -18,6 +18,7 @@ use glib::variant::ToVariant;
 | 
				
			|||||||
use gtk::PopoverExt;
 | 
					use gtk::PopoverExt;
 | 
				
			||||||
use gtk::WidgetExt;
 | 
					use gtk::WidgetExt;
 | 
				
			||||||
use std::io::Write;
 | 
					use std::io::Write;
 | 
				
			||||||
 | 
					use ::logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod variants {
 | 
					mod variants {
 | 
				
			||||||
    use glib;
 | 
					    use glib;
 | 
				
			||||||
@ -195,6 +196,82 @@ fn get_current_layout(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Translates all provided layout names according to current locale,
 | 
				
			||||||
 | 
					/// for the purpose of display (i.e. errors will be caught and reported)
 | 
				
			||||||
 | 
					fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
 | 
				
			||||||
 | 
					    // This procedure is rather ugly...
 | 
				
			||||||
 | 
					    // Xkb lookup *must not* be applied to non-system layouts,
 | 
				
			||||||
 | 
					    // so both translators can't be merged into one lookup table,
 | 
				
			||||||
 | 
					    // therefore must be done in two steps.
 | 
				
			||||||
 | 
					    // `XkbInfo` being temporary also means
 | 
				
			||||||
 | 
					    // that its return values must be copied,
 | 
				
			||||||
 | 
					    // forcing the use of `OwnedTranslation`.
 | 
				
			||||||
 | 
					    enum Status {
 | 
				
			||||||
 | 
					        /// xkb names should get all translated here
 | 
				
			||||||
 | 
					        Translated(OwnedTranslation),
 | 
				
			||||||
 | 
					        /// Builtin names need builtin translations
 | 
				
			||||||
 | 
					        Remaining(String),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Attempt to take all xkb names from gnome-desktop's xkb info.
 | 
				
			||||||
 | 
					    let xkb_translator = locale::XkbInfo::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let translated_names = layouts.iter()
 | 
				
			||||||
 | 
					        .map(|id| match id {
 | 
				
			||||||
 | 
					            LayoutId::System { name, kind: _ } => {
 | 
				
			||||||
 | 
					                xkb_translator.get_display_name(name)
 | 
				
			||||||
 | 
					                    .map(|s| Status::Translated(OwnedTranslation(s)))
 | 
				
			||||||
 | 
					                    .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                        eprintln!(
 | 
				
			||||||
 | 
					                            "No display name for xkb layout {}: {:?}",
 | 
				
			||||||
 | 
					                            name,
 | 
				
			||||||
 | 
					                            e,
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                        Status::Remaining(name.clone())
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            LayoutId::Local(name) => Status::Remaining(name.clone()),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Non-xkb layouts and weird xkb layouts
 | 
				
			||||||
 | 
					    // still need to be looked up in the internal database.
 | 
				
			||||||
 | 
					    let builtin_translations = system_locale()
 | 
				
			||||||
 | 
					        .map(|locale|
 | 
				
			||||||
 | 
					            locale.tags_for("messages")
 | 
				
			||||||
 | 
					                .next().unwrap() // guaranteed to exist
 | 
				
			||||||
 | 
					                .as_ref()
 | 
				
			||||||
 | 
					                .to_owned()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .or_warn("No locale detected")
 | 
				
			||||||
 | 
					        .and_then(|lang| {
 | 
				
			||||||
 | 
					            resources::get_layout_names(lang.as_str())
 | 
				
			||||||
 | 
					                .or_warn(&format!("No translations for locale {}", lang))
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match builtin_translations {
 | 
				
			||||||
 | 
					        Some(translations) => {
 | 
				
			||||||
 | 
					            translated_names
 | 
				
			||||||
 | 
					                .map(|status| match status {
 | 
				
			||||||
 | 
					                    Status::Remaining(name) => {
 | 
				
			||||||
 | 
					                        translations.get(name.as_str())
 | 
				
			||||||
 | 
					                            .unwrap_or(&Translation(name.as_str()))
 | 
				
			||||||
 | 
					                            .to_owned()
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    Status::Translated(t) => t,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .collect()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        None => {
 | 
				
			||||||
 | 
					            translated_names
 | 
				
			||||||
 | 
					                .map(|status| match status {
 | 
				
			||||||
 | 
					                    Status::Remaining(name) => OwnedTranslation(name),
 | 
				
			||||||
 | 
					                    Status::Translated(t) => t,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .collect()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn show(
 | 
					pub fn show(
 | 
				
			||||||
    window: EekGtkKeyboard,
 | 
					    window: EekGtkKeyboard,
 | 
				
			||||||
    position: Bounds,
 | 
					    position: Bounds,
 | 
				
			||||||
@ -219,68 +296,7 @@ pub fn show(
 | 
				
			|||||||
        .chain(overlay_layouts)
 | 
					        .chain(overlay_layouts)
 | 
				
			||||||
        .collect();
 | 
					        .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let translations = system_locale()
 | 
					    let translated_names = translate_layout_names(&all_layouts);
 | 
				
			||||||
        .map(|locale|
 | 
					 | 
				
			||||||
            locale.tags_for("messages")
 | 
					 | 
				
			||||||
                .next().unwrap() // guaranteed to exist
 | 
					 | 
				
			||||||
                .as_ref()
 | 
					 | 
				
			||||||
                .to_owned()
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        .and_then(|lang| resources::get_layout_names(lang.as_str()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The actual translation procedure attempts to take all xkb names
 | 
					 | 
				
			||||||
    // from gnome-desktop's xkb info.
 | 
					 | 
				
			||||||
    // Remaining names are translated using the internal database,
 | 
					 | 
				
			||||||
    // which is only available if the locale is set.
 | 
					 | 
				
			||||||
    // The result is a rather ugly and verbose translation procedure...
 | 
					 | 
				
			||||||
    enum Status {
 | 
					 | 
				
			||||||
        /// xkb names should get all translated here
 | 
					 | 
				
			||||||
        Translated(OwnedTranslation),
 | 
					 | 
				
			||||||
        /// Builtin names need builtin translations
 | 
					 | 
				
			||||||
        Remaining(String),
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    let xkb_translator = locale::XkbInfo::new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let translated_names = all_layouts.iter()
 | 
					 | 
				
			||||||
        .map(|id| match id {
 | 
					 | 
				
			||||||
            LayoutId::System { name, kind: _ } => {
 | 
					 | 
				
			||||||
                xkb_translator.get_display_name(name)
 | 
					 | 
				
			||||||
                    .map(|s| Status::Translated(OwnedTranslation(s)))
 | 
					 | 
				
			||||||
                    .unwrap_or_else(|e| {
 | 
					 | 
				
			||||||
                        eprintln!(
 | 
					 | 
				
			||||||
                            "No display name for xkb layout {}: {:?}",
 | 
					 | 
				
			||||||
                            name,
 | 
					 | 
				
			||||||
                            e,
 | 
					 | 
				
			||||||
                        );
 | 
					 | 
				
			||||||
                        Status::Remaining(name.clone())
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            LayoutId::Local(name) => Status::Remaining(name.clone()),
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let translated_names: Vec<OwnedTranslation> = match translations {
 | 
					 | 
				
			||||||
        Some(translations) => {
 | 
					 | 
				
			||||||
            translated_names
 | 
					 | 
				
			||||||
                .map(|status| match status {
 | 
					 | 
				
			||||||
                    Status::Remaining(name) => {
 | 
					 | 
				
			||||||
                        translations.get(name.as_str())
 | 
					 | 
				
			||||||
                            .unwrap_or(&Translation(name.as_str()))
 | 
					 | 
				
			||||||
                            .to_owned()
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    Status::Translated(t) => t,
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .collect()
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        None => {
 | 
					 | 
				
			||||||
            translated_names
 | 
					 | 
				
			||||||
                .map(|status| match status {
 | 
					 | 
				
			||||||
                    Status::Remaining(name) => OwnedTranslation(name),
 | 
					 | 
				
			||||||
                    Status::Translated(t) => t,
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .collect()
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // sorted collection of human and machine names
 | 
					    // sorted collection of human and machine names
 | 
				
			||||||
    let mut human_names: Vec<(OwnedTranslation, LayoutId)> = translated_names
 | 
					    let mut human_names: Vec<(OwnedTranslation, LayoutId)> = translated_names
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@
 | 
				
			|||||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
 | 
					 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! CSS data loading */
 | 
					/*! CSS data loading. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,6 +83,7 @@ fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
				
			|||||||
        .map_err(|e| {
 | 
					        .map_err(|e| {
 | 
				
			||||||
            match &e {
 | 
					            match &e {
 | 
				
			||||||
                env::VarError::NotPresent => {},
 | 
					                env::VarError::NotPresent => {},
 | 
				
			||||||
 | 
					                // maybe TODO: forward this warning?
 | 
				
			||||||
                e => eprintln!("GTK_THEME variable invalid: {}", e),
 | 
					                e => eprintln!("GTK_THEME variable invalid: {}", e),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            e
 | 
					            e
 | 
				
			||||||
@ -93,13 +94,15 @@ fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
				
			|||||||
        None => GtkTheme {
 | 
					        None => GtkTheme {
 | 
				
			||||||
            name: {
 | 
					            name: {
 | 
				
			||||||
                settings.get_property("gtk-theme-name")
 | 
					                settings.get_property("gtk-theme-name")
 | 
				
			||||||
                    .ok_warn("No theme name")
 | 
					                    // maybe TODO: is this worth a warning?
 | 
				
			||||||
 | 
					                    .or_warn("No theme name")
 | 
				
			||||||
                    .and_then(|value| value.get::<String>())
 | 
					                    .and_then(|value| value.get::<String>())
 | 
				
			||||||
                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
					                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            variant: {
 | 
					            variant: {
 | 
				
			||||||
                settings.get_property("gtk-application-prefer-dark-theme")
 | 
					                settings.get_property("gtk-application-prefer-dark-theme")
 | 
				
			||||||
                    .ok_warn("No settings key")
 | 
					                    // maybe TODO: is this worth a warning?
 | 
				
			||||||
 | 
					                    .or_warn("No settings key")
 | 
				
			||||||
                    .and_then(|value| value.get::<bool>())
 | 
					                    .and_then(|value| value.get::<bool>())
 | 
				
			||||||
                    .and_then(|dark_preferred| match dark_preferred {
 | 
					                    .and_then(|dark_preferred| match dark_preferred {
 | 
				
			||||||
                        true => Some("dark".into()),
 | 
					                        true => Some("dark".into()),
 | 
				
			||||||
 | 
				
			|||||||
@ -190,6 +190,11 @@ impl<T> Borrow<Rc<T>> for Pointer<T> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait WarningHandler {
 | 
				
			||||||
 | 
					    /// Handle a warning
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user