@@ -21,7 +21,7 @@ use handlebars::{to_json, Handlebars};
2121use tauri_utils:: config:: { NSISInstallerMode , NsisCompression , WebviewInstallMode } ;
2222
2323use std:: {
24- collections:: { BTreeMap , HashMap } ,
24+ collections:: BTreeMap ,
2525 fs,
2626 path:: { Path , PathBuf } ,
2727 process:: Command ,
@@ -213,43 +213,42 @@ fn build_nsis_app_installer(
213213 to_json ( settings. windows ( ) . allow_downgrades ) ,
214214 ) ;
215215
216- if let Some ( license) = settings. license_file ( ) {
217- data. insert ( "license" , to_json ( dunce:: canonicalize ( license) ?) ) ;
216+ if let Some ( license_file) = settings. license_file ( ) {
217+ let license_file = dunce:: canonicalize ( license_file) ?;
218+ let license_file_with_bom = output_path. join ( "license_file" ) ;
219+ let content = std:: fs:: read ( license_file) ?;
220+ write_utf8_with_bom ( & license_file_with_bom, content) ?;
221+ data. insert ( "license" , to_json ( license_file_with_bom) ) ;
218222 }
219223
220- let mut install_mode = NSISInstallerMode :: CurrentUser ;
221- let mut languages = vec ! [ "English" . into( ) ] ;
222- let mut custom_template_path = None ;
223- let mut custom_language_files = None ;
224- if let Some ( nsis) = & settings. windows ( ) . nsis {
225- custom_template_path. clone_from ( & nsis. template ) ;
226- custom_language_files. clone_from ( & nsis. custom_language_files ) ;
227- install_mode = nsis. install_mode ;
228- if let Some ( langs) = & nsis. languages {
229- languages. clear ( ) ;
230- languages. extend_from_slice ( langs) ;
231- }
224+ let nsis = settings. windows ( ) . nsis . as_ref ( ) ;
225+
226+ let custom_template_path = nsis. as_ref ( ) . and_then ( |n| n. template . clone ( ) ) ;
227+
228+ let install_mode = nsis
229+ . as_ref ( )
230+ . map ( |n| n. install_mode )
231+ . unwrap_or ( NSISInstallerMode :: CurrentUser ) ;
232+
233+ if let Some ( nsis) = nsis {
232234 if let Some ( installer_icon) = & nsis. installer_icon {
233235 data. insert (
234236 "installer_icon" ,
235237 to_json ( dunce:: canonicalize ( installer_icon) ?) ,
236238 ) ;
237239 }
240+
238241 if let Some ( header_image) = & nsis. header_image {
239242 data. insert ( "header_image" , to_json ( dunce:: canonicalize ( header_image) ?) ) ;
240243 }
244+
241245 if let Some ( sidebar_image) = & nsis. sidebar_image {
242246 data. insert (
243247 "sidebar_image" ,
244248 to_json ( dunce:: canonicalize ( sidebar_image) ?) ,
245249 ) ;
246250 }
247251
248- data. insert (
249- "display_language_selector" ,
250- to_json ( nsis. display_language_selector && languages. len ( ) > 1 ) ,
251- ) ;
252-
253252 if let Some ( installer_hooks) = & nsis. installer_hooks {
254253 let installer_hooks = dunce:: canonicalize ( installer_hooks) ?;
255254 data. insert ( "installer_hooks" , to_json ( installer_hooks) ) ;
@@ -281,26 +280,48 @@ fn build_nsis_app_installer(
281280 } ) ,
282281 ) ;
283282
284- let mut languages_data = Vec :: new ( ) ;
285- for lang in & languages {
286- if let Some ( data) = get_lang_data ( lang, custom_language_files. as_ref ( ) ) ? {
287- languages_data. push ( data) ;
288- } else {
289- log:: warn!( "Custom tauri messages for {lang} are not translated.\n If it is a valid language listed on <https://github.com/kichik/nsis/tree/9465c08046f00ccb6eda985abbdbf52c275c6c4d/Contrib/Language%20files>, please open a Tauri feature request\n or you can provide a custom language file for it in `tauri.conf.json > bundle > windows > nsis > custom_language_files`" ) ;
290- }
291- }
292-
283+ let languages = nsis
284+ . and_then ( |nsis| nsis. languages . clone ( ) )
285+ . unwrap_or_else ( || vec ! [ "English" . into( ) ] ) ;
293286 data. insert ( "languages" , to_json ( languages. clone ( ) ) ) ;
287+
294288 data. insert (
295- "language_files " ,
289+ "display_language_selector " ,
296290 to_json (
297- languages_data
298- . iter ( )
299- . map ( |d| d. 0 . clone ( ) )
300- . collect :: < Vec < _ > > ( ) ,
291+ nsis
292+ . map ( |nsis| nsis. display_language_selector && languages. len ( ) > 1 )
293+ . unwrap_or ( false ) ,
301294 ) ,
302295 ) ;
303296
297+ let custom_language_files = nsis. and_then ( |nsis| nsis. custom_language_files . clone ( ) ) ;
298+
299+ let mut language_files_paths = Vec :: new ( ) ;
300+ for lang in & languages {
301+ // if user provided a custom lang file, we rewrite it with BOM
302+ if let Some ( path) = custom_language_files. as_ref ( ) . and_then ( |h| h. get ( lang) ) {
303+ let path = dunce:: canonicalize ( path) ?;
304+ let path_with_bom = path
305+ . file_name ( )
306+ . map ( |f| output_path. join ( f) )
307+ . unwrap_or_else ( || output_path. join ( format ! ( "{lang}_custom.nsh" ) ) ) ;
308+ let content = std:: fs:: read ( path) ?;
309+ write_utf8_with_bom ( & path_with_bom, content) ?;
310+ language_files_paths. push ( path_with_bom) ;
311+ } else {
312+ // if user has not provided a custom lang file,
313+ // we check our translated languages
314+ if let Some ( ( file_name, content) ) = get_lang_data ( lang) {
315+ let path = output_path. join ( file_name) ;
316+ write_utf8_with_bom ( & path, content) ?;
317+ language_files_paths. push ( path) ;
318+ } else {
319+ log:: warn!( "Custom tauri messages for {lang} are not translated.\n If it is a valid language listed on <https://github.com/kichik/nsis/tree/9465c08046f00ccb6eda985abbdbf52c275c6c4d/Contrib/Language%20files>, please open a Tauri feature request\n or you can provide a custom language file for it in `tauri.conf.json > bundle > windows > nsis > custom_language_files`" ) ;
320+ }
321+ }
322+ }
323+ data. insert ( "language_files" , to_json ( language_files_paths) ) ;
324+
304325 let main_binary = settings
305326 . binaries ( )
306327 . iter ( )
@@ -463,27 +484,21 @@ fn build_nsis_app_installer(
463484 . expect ( "Failed to setup handlebar template" ) ;
464485 }
465486
466- write_ut16_le_with_bom (
487+ write_utf8_with_bom (
467488 output_path. join ( "FileAssociation.nsh" ) ,
468- include_str ! ( "./templates/FileAssociation.nsh" ) ,
489+ include_bytes ! ( "./templates/FileAssociation.nsh" ) ,
469490 ) ?;
470- write_ut16_le_with_bom (
491+ write_utf8_with_bom (
471492 output_path. join ( "utils.nsh" ) ,
472- include_str ! ( "./templates/utils.nsh" ) ,
493+ include_bytes ! ( "./templates/utils.nsh" ) ,
473494 ) ?;
474495
475496 let installer_nsi_path = output_path. join ( "installer.nsi" ) ;
476- write_ut16_le_with_bom (
497+ write_utf8_with_bom (
477498 & installer_nsi_path,
478- handlebars. render ( "installer.nsi" , & data) ?. as_str ( ) ,
499+ handlebars. render ( "installer.nsi" , & data) ?,
479500 ) ?;
480501
481- for ( lang, data) in languages_data. iter ( ) {
482- if let Some ( content) = data {
483- write_ut16_le_with_bom ( output_path. join ( lang) . with_extension ( "nsh" ) , content) ?;
484- }
485- }
486-
487502 let package_base_name = format ! (
488503 "{}_{}_{}-setup" ,
489504 settings. product_name( ) ,
@@ -511,6 +526,7 @@ fn build_nsis_app_installer(
511526 let mut nsis_cmd = Command :: new ( "makensis" ) ;
512527
513528 nsis_cmd
529+ . args ( [ "-INPUTCHARSET" , "UTF8" , "-OUTPUTCHARSET" , "UTF8" ] )
514530 . arg ( match settings. log_level ( ) {
515531 log:: Level :: Error => "-V1" ,
516532 log:: Level :: Warn => "-V2" ,
@@ -662,50 +678,38 @@ fn generate_estimated_size(
662678 Ok ( format ! ( "{size:#08x}" ) )
663679}
664680
665- fn get_lang_data (
666- lang : & str ,
667- custom_lang_files : Option < & HashMap < String , PathBuf > > ,
668- ) -> crate :: Result < Option < ( PathBuf , Option < & ' static str > ) > > {
669- if let Some ( path) = custom_lang_files. and_then ( |h| h. get ( lang) ) {
670- return Ok ( Some ( ( dunce:: canonicalize ( path) ?, None ) ) ) ;
671- }
672-
673- let lang_path = PathBuf :: from ( format ! ( "{lang}.nsh" ) ) ;
674- let lang_content = match lang. to_lowercase ( ) . as_str ( ) {
675- "arabic" => Some ( include_str ! ( "./templates/nsis-languages/Arabic.nsh" ) ) ,
676- "bulgarian" => Some ( include_str ! ( "./templates/nsis-languages/Bulgarian.nsh" ) ) ,
677- "dutch" => Some ( include_str ! ( "./templates/nsis-languages/Dutch.nsh" ) ) ,
678- "english" => Some ( include_str ! ( "./templates/nsis-languages/English.nsh" ) ) ,
679- "german" => Some ( include_str ! ( "./templates/nsis-languages/German.nsh" ) ) ,
680- "japanese" => Some ( include_str ! ( "./templates/nsis-languages/Japanese.nsh" ) ) ,
681- "korean" => Some ( include_str ! ( "./templates/nsis-languages/Korean.nsh" ) ) ,
682- "portuguesebr" => Some ( include_str ! ( "./templates/nsis-languages/PortugueseBR.nsh" ) ) ,
683- "russian" => Some ( include_str ! ( "./templates/nsis-languages/Russian.nsh" ) ) ,
684- "tradchinese" => Some ( include_str ! ( "./templates/nsis-languages/TradChinese.nsh" ) ) ,
685- "simpchinese" => Some ( include_str ! ( "./templates/nsis-languages/SimpChinese.nsh" ) ) ,
686- "french" => Some ( include_str ! ( "./templates/nsis-languages/French.nsh" ) ) ,
687- "spanish" => Some ( include_str ! ( "./templates/nsis-languages/Spanish.nsh" ) ) ,
688- "spanishinternational" => Some ( include_str ! (
689- "./templates/nsis-languages/SpanishInternational.nsh"
690- ) ) ,
691- "persian" => Some ( include_str ! ( "./templates/nsis-languages/Persian.nsh" ) ) ,
692- "turkish" => Some ( include_str ! ( "./templates/nsis-languages/Turkish.nsh" ) ) ,
693- "swedish" => Some ( include_str ! ( "./templates/nsis-languages/Swedish.nsh" ) ) ,
694- _ => return Ok ( None ) ,
681+ fn get_lang_data ( lang : & str ) -> Option < ( String , & [ u8 ] ) > {
682+ let path = format ! ( "{lang}.nsh" ) ;
683+ let content: & [ u8 ] = match lang. to_lowercase ( ) . as_str ( ) {
684+ "arabic" => include_bytes ! ( "./templates/nsis-languages/Arabic.nsh" ) ,
685+ "bulgarian" => include_bytes ! ( "./templates/nsis-languages/Bulgarian.nsh" ) ,
686+ "dutch" => include_bytes ! ( "./templates/nsis-languages/Dutch.nsh" ) ,
687+ "english" => include_bytes ! ( "./templates/nsis-languages/English.nsh" ) ,
688+ "german" => include_bytes ! ( "./templates/nsis-languages/German.nsh" ) ,
689+ "japanese" => include_bytes ! ( "./templates/nsis-languages/Japanese.nsh" ) ,
690+ "korean" => include_bytes ! ( "./templates/nsis-languages/Korean.nsh" ) ,
691+ "portuguesebr" => include_bytes ! ( "./templates/nsis-languages/PortugueseBR.nsh" ) ,
692+ "russian" => include_bytes ! ( "./templates/nsis-languages/Russian.nsh" ) ,
693+ "tradchinese" => include_bytes ! ( "./templates/nsis-languages/TradChinese.nsh" ) ,
694+ "simpchinese" => include_bytes ! ( "./templates/nsis-languages/SimpChinese.nsh" ) ,
695+ "french" => include_bytes ! ( "./templates/nsis-languages/French.nsh" ) ,
696+ "spanish" => include_bytes ! ( "./templates/nsis-languages/Spanish.nsh" ) ,
697+ "spanishinternational" => include_bytes ! ( "./templates/nsis-languages/SpanishInternational.nsh" ) ,
698+ "persian" => include_bytes ! ( "./templates/nsis-languages/Persian.nsh" ) ,
699+ "turkish" => include_bytes ! ( "./templates/nsis-languages/Turkish.nsh" ) ,
700+ "swedish" => include_bytes ! ( "./templates/nsis-languages/Swedish.nsh" ) ,
701+ _ => return None ,
695702 } ;
696-
697- Ok ( Some ( ( lang_path, lang_content) ) )
703+ Some ( ( path, content) )
698704}
699705
700- fn write_ut16_le_with_bom < P : AsRef < Path > > ( path : P , content : & str ) -> crate :: Result < ( ) > {
706+ fn write_utf8_with_bom < P : AsRef < Path > , C : AsRef < [ u8 ] > > ( path : P , content : C ) -> crate :: Result < ( ) > {
701707 use std:: fs:: File ;
702708 use std:: io:: { BufWriter , Write } ;
703709
704710 let file = File :: create ( path) ?;
705711 let mut output = BufWriter :: new ( file) ;
706- output. write_all ( & [ 0xFF , 0xFE ] ) ?; // the BOM part
707- for utf16 in content. encode_utf16 ( ) {
708- output. write_all ( & utf16. to_le_bytes ( ) ) ?;
709- }
712+ output. write_all ( & [ 0xEF , 0xBB , 0xBF ] ) ?; // UTF-8 BOM
713+ output. write_all ( content. as_ref ( ) ) ?;
710714 Ok ( ( ) )
711715}
0 commit comments