@@ -6,6 +6,7 @@ use crate::Translator;
6
6
use error_chain:: { bail, error_chain} ;
7
7
use std:: collections:: HashMap ;
8
8
use std:: fs;
9
+ use std:: sync:: Arc ;
9
10
10
11
// This has no foreign links because everything to do with config management should be isolated and generic
11
12
error_chain ! {
@@ -29,12 +30,15 @@ error_chain! {
29
30
}
30
31
}
31
32
32
- /// A trait for systems that manage where to put configuration files . At simplest, we'll just write them to static files, but they're
33
- /// more likely to be stored on a CMS.
33
+ /// A trait for systems that manage where to put translations . At simplest, we'll just write them to static files, but they might also
34
+ /// be stored in a CMS.
34
35
#[ async_trait:: async_trait]
35
36
pub trait TranslationsManager : Clone {
36
- /// Gets translations for the given locale.
37
+ /// Gets a translator for the given locale.
37
38
async fn get_translator_for_locale ( & self , locale : String ) -> Result < Translator > ;
39
+ /// Gets the translations in stirng format for the given locale (avoids deserialize-then-serialize). This should NOT include the
40
+ /// translator's `locale` property, it should simply be a `HashMap<String, String>` in JSON format.
41
+ async fn get_translations_str_for_locale ( & self , locale : String ) -> Result < String > ;
38
42
}
39
43
40
44
/// The default translations manager. This will store static files in the specified location on disk. This should be suitable for
@@ -43,16 +47,26 @@ pub trait TranslationsManager: Clone {
43
47
#[ derive( Clone ) ]
44
48
pub struct FsTranslationsManager {
45
49
root_path : String ,
50
+ /// A map of locales to cached translators. This decreases the number of file reads significantly for the locales specified. This
51
+ /// does NOT cache dynamically, and will only cache the requested locales.
52
+ cached_translators : HashMap < String , Arc < Translator > > ,
53
+ /// The locales being cached for easier access.
54
+ cached_locales : Vec < String >
46
55
}
56
+ // TODO implement caching
47
57
impl FsTranslationsManager {
48
58
/// Creates a new filesystem translations manager. You should provide a path like `/translations` here.
49
59
pub fn new ( root_path : String ) -> Self {
50
- Self { root_path }
60
+ Self {
61
+ root_path,
62
+ cached_translators : HashMap :: new ( ) ,
63
+ cached_locales : Vec :: new ( )
64
+ }
51
65
}
52
66
}
53
67
#[ async_trait:: async_trait]
54
68
impl TranslationsManager for FsTranslationsManager {
55
- async fn get_translator_for_locale ( & self , locale : String ) -> Result < Translator > {
69
+ async fn get_translations_str_for_locale ( & self , locale : String ) -> Result < String > {
56
70
// The file must be named as the locale it describes
57
71
let asset_path = format ! ( "{}/{}.json" , self . root_path, locale) ;
58
72
let translations_str = match fs:: metadata ( & asset_path) {
@@ -63,9 +77,14 @@ impl TranslationsManager for FsTranslationsManager {
63
77
}
64
78
Err ( err) => bail ! ( ErrorKind :: ReadFailed ( locale. to_string( ) , err. to_string( ) ) ) ,
65
79
} ;
80
+
81
+ Ok ( translations_str)
82
+ }
83
+ async fn get_translator_for_locale ( & self , locale : String ) -> Result < Translator > {
84
+ let translations_str = self . get_translations_str_for_locale ( locale. clone ( ) ) . await ?;
66
85
// We expect the translations defined there, but not the locale itself
67
86
let translations = serde_json:: from_str :: < HashMap < String , String > > ( & translations_str)
68
- . map_err ( |err| ErrorKind :: SerializationFailed ( locale. to_string ( ) , err. to_string ( ) ) ) ?;
87
+ . map_err ( |err| ErrorKind :: SerializationFailed ( locale. clone ( ) , err. to_string ( ) ) ) ?;
69
88
let translator = Translator :: new ( locale, translations) ;
70
89
71
90
Ok ( translator)
0 commit comments