11//! The major configuration file for this app, containing information about which version to skip,
22//! when the updates are checked, how long until next updates will be checked etc.
33
4+ use crate :: setter;
5+ use crate :: { dirs:: rim_config_dir, types:: TomlParser } ;
46use anyhow:: Result ;
57use chrono:: { NaiveDateTime , Utc } ;
6- use rim_common:: { dirs:: rim_config_dir, types:: TomlParser } ;
78use serde:: { Deserialize , Serialize } ;
9+ use std:: str:: FromStr ;
810use std:: { collections:: HashMap , fmt:: Display , time:: Duration } ;
911
1012/// Default update check timeout is 1440 minutes (1 day)
@@ -15,6 +17,7 @@ pub const DEFAULT_UPDATE_CHECK_DURATION: Duration =
1517
1618#[ derive( Debug , Deserialize , Serialize , Default ) ]
1719pub struct Configuration {
20+ pub language : Option < Language > ,
1821 pub update : UpdateCheckerOpt ,
1922}
2023
@@ -36,12 +39,17 @@ impl Configuration {
3639 self
3740 }
3841
39- /// Try loading from [`rim_config_dir`].
42+ /// Try loading from [`rim_config_dir`], return `None` if it doesn't exists yet.
43+ pub fn try_load_from_config_dir ( ) -> Option < Self > {
44+ Self :: load_from_dir ( rim_config_dir ( ) ) . ok ( )
45+ }
46+
47+ /// Loading from [`rim_config_dir`] or return default.
4048 ///
4149 /// This guarantee to return a [`VersionSkip`] object,
4250 /// even if the file does not exists, the default will got returned.
4351 pub fn load_from_config_dir ( ) -> Self {
44- Self :: load_from_dir ( rim_config_dir ( ) ) . unwrap_or_default ( )
52+ Self :: try_load_from_config_dir ( ) . unwrap_or_default ( )
4553 }
4654
4755 /// Write the configuration to [`rim_config_dir`].
@@ -52,6 +60,51 @@ impl Configuration {
5260 pub fn update_skipped < T : AsRef < str > > ( & self , target : UpdateTarget , version : T ) -> bool {
5361 self . update . is_skipped ( target, version)
5462 }
63+
64+ setter ! ( set_language( self . language, Option <Language >) ) ;
65+ }
66+
67+ #[ derive( Debug , Deserialize , Serialize , Default , PartialEq , Eq ) ]
68+ #[ non_exhaustive]
69+ pub enum Language {
70+ CN ,
71+ #[ default]
72+ EN ,
73+ }
74+
75+ impl Language {
76+ pub fn possible_values ( ) -> & ' static [ Language ] {
77+ & [ Self :: CN , Self :: EN ]
78+ }
79+ /// Returns the string representation of this enum,
80+ /// this will be the same one that parsed from commandline input.
81+ pub fn as_str ( & self ) -> & ' static str {
82+ match self {
83+ Self :: CN => "cn" ,
84+ Self :: EN => "en" ,
85+ }
86+ }
87+ /// This is the `str` used for setting locale,
88+ /// make sure the values match the filenames under `<root>/locales`.
89+ pub fn locale_str ( & self ) -> & str {
90+ match self {
91+ Self :: CN => "zh-CN" ,
92+ Self :: EN => "en-US" ,
93+ }
94+ }
95+ }
96+
97+ impl FromStr for Language {
98+ type Err = anyhow:: Error ;
99+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
100+ match s. to_lowercase ( ) . as_str ( ) {
101+ "cn" | "zh-cn" => Ok ( Self :: CN ) ,
102+ "en" | "en-us" => Ok ( Self :: EN ) ,
103+ _ => Err ( anyhow:: anyhow!(
104+ "invalid or unsupported language option: {s}"
105+ ) ) ,
106+ }
107+ }
55108}
56109
57110// If we ever need to support more things for update checker,
@@ -227,4 +280,19 @@ manager = { last-run = "1970-01-01T00:00:00" }"#;
227280 expected = expected. remind_later ( manager, 60 ) ;
228281 assert_eq ! ( expected. conf_mut( manager) . timeout, Some ( 120 ) ) ;
229282 }
283+
284+ #[ test]
285+ fn lang_config ( ) {
286+ let input = r#"language = "CN"
287+
288+ [update]
289+ "# ;
290+
291+ let expected = Configuration :: from_str ( input) . unwrap ( ) ;
292+ assert_eq ! ( expected. language, Some ( Language :: CN ) ) ;
293+
294+ // check if the language consistance since we have a `FromStr` impl for it.
295+ let back_to_str = toml:: to_string ( & expected) . unwrap ( ) ;
296+ assert_eq ! ( back_to_str, input) ;
297+ }
230298}
0 commit comments