1- use serde:: { Deserialize , Serialize } ;
1+ use serde:: { Deserialize , Serialize , Serializer , ser :: SerializeMap } ;
22use std:: {
33 collections:: HashMap ,
44 io:: { BufRead , Write } ,
@@ -11,12 +11,28 @@ use crate::{
1111 types:: { Entry , EntryStatus , Metadata , Plural , PluralCategory , Resource , Translation } ,
1212} ;
1313
14+ fn serialize_sorted_map < S , V > ( map : & HashMap < String , V > , serializer : S ) -> Result < S :: Ok , S :: Error >
15+ where
16+ S : Serializer ,
17+ V : Serialize ,
18+ {
19+ let mut keys: Vec < & String > = map. keys ( ) . collect ( ) ;
20+ keys. sort_unstable ( ) ;
21+
22+ let mut out = serializer. serialize_map ( Some ( map. len ( ) ) ) ?;
23+ for k in keys {
24+ out. serialize_entry ( k, & map[ k] ) ?;
25+ }
26+ out. end ( )
27+ }
28+
1429#[ derive( Debug , Clone , PartialEq , Eq , Deserialize , Serialize ) ]
1530#[ serde( rename_all = "camelCase" ) ]
1631pub struct Format {
1732 pub source_language : String ,
18- pub version : String ,
33+ # [ serde ( serialize_with = "serialize_sorted_map" ) ]
1934 pub strings : HashMap < String , Item > ,
35+ pub version : String ,
2036}
2137
2238impl Parser for Format {
@@ -230,20 +246,25 @@ impl TryFrom<Format> for Vec<Resource> {
230246 }
231247}
232248
249+ fn is_none_or_true ( v : & Option < bool > ) -> bool {
250+ v. is_none ( ) || * v == Some ( true )
251+ }
252+
233253#[ derive( Debug , Clone , PartialEq , Eq , Deserialize , Serialize ) ]
234254#[ serde( rename_all = "camelCase" ) ]
235255pub struct Item {
236- #[ serde( default ) ]
237- #[ serde( skip_serializing_if = "HashMap::is_empty" ) ]
238- pub localizations : HashMap < String , Localization > ,
239256 #[ serde( skip_serializing_if = "Option::is_none" ) ]
240257 pub comment : Option < String > ,
241258 #[ serde( skip_serializing_if = "Option::is_none" ) ]
242- pub extraction_state : Option < ExtractionState > ,
259+ pub is_comment_auto_generated : Option < bool > ,
243260 #[ serde( skip_serializing_if = "Option::is_none" ) ]
261+ pub extraction_state : Option < ExtractionState > ,
262+ #[ serde( skip_serializing_if = "is_none_or_true" ) ]
244263 pub should_translate : Option < bool > ,
245- #[ serde( skip_serializing_if = "Option::is_none" ) ]
246- pub is_comment_auto_generated : Option < bool > ,
264+ #[ serde( default ) ]
265+ #[ serde( serialize_with = "serialize_sorted_map" ) ]
266+ #[ serde( skip_serializing_if = "HashMap::is_empty" ) ]
267+ pub localizations : HashMap < String , Localization > ,
247268}
248269
249270impl Item {
@@ -666,7 +687,9 @@ mod tests {
666687 assert ! ( item. localizations. is_empty( ) ) ;
667688 assert_eq ! (
668689 item. comment. as_deref( ) ,
669- Some ( "Text displayed in the tips view of the return user reward dialog, describing the rewards that have been sent to the user's backpack." )
690+ Some (
691+ "Text displayed in the tips view of the return user reward dialog, describing the rewards that have been sent to the user's backpack."
692+ )
670693 ) ;
671694 assert_eq ! ( item. is_comment_auto_generated, Some ( true ) ) ;
672695 }
0 commit comments