@@ -2,6 +2,7 @@ use crate::formats::parse_custom_format;
22use crate :: transformers:: custom_format_to_resource;
33
44use langcodec:: { Codec , converter} ;
5+ use rayon:: prelude:: * ;
56
67/// Strategy for handling conflicts when merging localization files.
78#[ derive( Debug , Clone , PartialEq , clap:: ValueEnum ) ]
@@ -26,29 +27,28 @@ pub fn run_merge_command(
2627 std:: process:: exit ( 1 ) ;
2728 }
2829
29- // Read all input files into a single codec
30- let mut codec = Codec :: new ( ) ;
31- for ( i, input) in inputs. iter ( ) . enumerate ( ) {
32- println ! ( "Reading file {}/{}: {}" , i + 1 , inputs. len( ) , input) ;
33-
34- // Try standard format first
35- if let Ok ( ( ) ) = codec. read_file_by_extension ( input, lang. clone ( ) ) {
36- continue ;
37- }
38-
39- // If standard format fails, try custom format for JSON/YAML files
40- if ( input. ends_with ( ".json" ) || input. ends_with ( ".yaml" ) || input. ends_with ( ".yml" ) )
41- && let Ok ( ( ) ) = try_custom_format_merge ( input, lang. clone ( ) , & mut codec)
42- {
43- continue ;
30+ // Read all input files concurrently into Codecs, then combine and merge
31+ println ! ( "Reading {} input files..." , inputs. len( ) ) ;
32+ let read_results: Vec < Result < Codec , String > > = inputs
33+ . par_iter ( )
34+ . map ( |input| read_input_to_codec ( input, lang. clone ( ) ) )
35+ . collect ( ) ;
36+
37+ let mut input_codecs: Vec < Codec > = Vec :: with_capacity ( read_results. len ( ) ) ;
38+ for ( idx, res) in read_results. into_iter ( ) . enumerate ( ) {
39+ match res {
40+ Ok ( c) => input_codecs. push ( c) ,
41+ Err ( e) => {
42+ println ! ( "❌ Error reading input file {}/{}" , idx + 1 , inputs. len( ) ) ;
43+ eprintln ! ( "{}" , e) ;
44+ std:: process:: exit ( 1 ) ;
45+ }
4446 }
45-
46- // If both fail, show error
47- println ! ( "❌ Error reading input file" ) ;
48- eprintln ! ( "Error reading {}: unsupported format" , input) ;
49- std:: process:: exit ( 1 ) ;
5047 }
5148
49+ // Combine all input codecs first, then merge by language
50+ let mut codec = Codec :: from_codecs ( input_codecs) ;
51+
5252 // Skip validation for merge operations since we expect multiple resources with potentially duplicate languages
5353
5454 // Merge resources using the new lib crate method
@@ -133,30 +133,49 @@ pub fn run_merge_command(
133133 ) ;
134134}
135135
136- /// Try to read a custom format file and add it to the codec
137- fn try_custom_format_merge (
136+ /// Read a single input file into a vector of Resources, supporting both standard and custom formats
137+ fn read_input_to_resources (
138138 input : & str ,
139- _lang : Option < String > ,
140- codec : & mut Codec ,
141- ) -> Result < ( ) , String > {
142- // Validate custom format file
143- crate :: validation:: validate_custom_format_file ( input) ?;
144-
145- // Auto-detect format based on file content
146- let file_content = std:: fs:: read_to_string ( input)
147- . map_err ( |e| format ! ( "Error reading file {}: {}" , input, e) ) ?;
148-
149- // Validate file content
150- crate :: formats:: validate_custom_format_content ( input, & file_content) ?;
151-
152- // Convert custom format to Resource
153- let resources =
154- custom_format_to_resource ( input. to_string ( ) , parse_custom_format ( "json-language-map" ) ?) ?;
155-
156- // Add resources to codec
157- for resource in resources {
158- codec. add_resource ( resource) ;
139+ lang : Option < String > ,
140+ ) -> Result < Vec < langcodec:: Resource > , String > {
141+ // Try standard format via lib crate (uses extension + language inference)
142+ {
143+ let mut local_codec = Codec :: new ( ) ;
144+ if let Ok ( ( ) ) = local_codec. read_file_by_extension ( input, lang. clone ( ) ) {
145+ return Ok ( local_codec. resources ) ;
146+ }
159147 }
160148
161- Ok ( ( ) )
149+ // Try custom JSON/YAML formats (for merge, we follow the existing JSON-language-map behavior)
150+ if input. ends_with ( ".json" ) || input. ends_with ( ".yaml" ) || input. ends_with ( ".yml" ) {
151+ // Validate custom format file
152+ crate :: validation:: validate_custom_format_file ( input)
153+ . map_err ( |e| format ! ( "Failed to validate {}: {}" , input, e) ) ?;
154+
155+ // Auto-detect format based on file content
156+ let file_content = std:: fs:: read_to_string ( input)
157+ . map_err ( |e| format ! ( "Error reading file {}: {}" , input, e) ) ?;
158+
159+ // Validate file content (ignore returned format; keep parity with existing merge behavior)
160+ crate :: formats:: validate_custom_format_content ( input, & file_content)
161+ . map_err ( |e| format ! ( "Invalid custom format {}: {}" , input, e) ) ?;
162+
163+ // Convert custom format to Resource using JSON language map to match current merge behavior
164+ let resources = custom_format_to_resource (
165+ input. to_string ( ) ,
166+ parse_custom_format ( "json-language-map" )
167+ . map_err ( |e| format ! ( "Failed to parse custom format: {}" , e) ) ?,
168+ )
169+ . map_err ( |e| format ! ( "Failed to convert custom format {}: {}" , input, e) ) ?;
170+
171+ return Ok ( resources) ;
172+ }
173+
174+ Err ( format ! ( "Error reading {}: unsupported format" , input) )
175+ }
176+
177+ /// Read a single input into a Codec (wrapper over read_input_to_resources)
178+ fn read_input_to_codec ( input : & str , lang : Option < String > ) -> Result < Codec , String > {
179+ let resources = read_input_to_resources ( input, lang) ?;
180+ Ok ( Codec { resources } )
162181}
0 commit comments