From df067274165d54bc6c55534b3b57ef72789db089 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 15 Oct 2013 22:58:27 +0100 Subject: [PATCH] [loc] add localization support * This is a merge up to commit bd319269aae59fbaead0d3ed6e1d7d340813fd42 of the localization branch * Also fixes Clang warnings --- res/localization/rufus.loc | 690 ++++++++++++++++++++++++++++++++ src/.msvc/rufus.vcxproj | 7 + src/.msvc/rufus.vcxproj.filters | 9 + src/.msvc/rufus_sources | 1 + src/Makefile.am | 2 +- src/Makefile.in | 23 +- src/badblocks.c | 14 +- src/drive.c | 5 +- src/format.c | 64 ++- src/iso.c | 17 +- src/license.h | 27 +- src/localization.c | 368 +++++++++++++++++ src/localization.h | 158 ++++++++ src/localization_data.h | 382 ++++++++++++++++++ src/localization_data.sh | 89 ++++ src/msapi_utf8.h | 42 ++ src/net.c | 21 +- src/parser.c | 458 +++++++++++++++++++-- src/resource.h | 303 +++++++++++++- src/rufus.c | 417 +++++++++---------- src/rufus.h | 23 +- src/rufus.rc | 77 ++-- src/stdfn.c | 4 +- src/stdio.c | 95 ++--- src/stdlg.c | 216 +++++++--- src/syslinux.c | 3 +- 26 files changed, 3024 insertions(+), 491 deletions(-) create mode 100644 res/localization/rufus.loc create mode 100644 src/localization.c create mode 100644 src/localization.h create mode 100644 src/localization_data.h create mode 100644 src/localization_data.sh diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc new file mode 100644 index 00000000..fb1edfa8 --- /dev/null +++ b/res/localization/rufus.loc @@ -0,0 +1,690 @@ +# This file should be saved as UTF-8, no-BOM + +################################################################################ +l "en_US" "English (US)" 0x0409, 0x0809, 0x0c09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x3809, 0x3c09, 0x4009, 0x4409, 0x4809 +g IDD_MESSAGES +t MSG_001 "Other instance detected" +t MSG_002 "Another Rufus application is running.\n" + "Please close the first application before running another one." +t MSG_003 "WARNING: ALL DATA ON DEVICE '%s' WILL BE DESTROYED.\n" + "To continue with this operation, click OK. To quit click CANCEL." +t MSG_004 "Rufus update policy" +t MSG_005 "Do you want to allow Rufus to check for application updates online?" +t MSG_006 "Close" # Must be the same as IDD_DIALOG:IDCANCEL (i.e. "Close" - I know it's confusing) +t MSG_007 "Cancel" +t MSG_008 "Yes" +t MSG_009 "No" +t MSG_010 "Bad blocks found" +t MSG_011 "Check completed: %u bad block(s) found\n" + " %d read error(s)\n %d write error(s)\n %d corruption error(s)\n" +# The following will contain the formatted message above as well as the name of the bad blocks logfile +t MSG_012 "%s\nA more detailed report can be found in:\n%s" +t MSG_013 "Disabled" +t MSG_014 "Daily" +t MSG_015 "Weekly" +t MSG_016 "Monthly" +t MSG_017 "Custom" +t MSG_018 "Your version: %d.%d.%d (Build %d)" +t MSG_019 "Latest version: %d.%d.%d (Build %d)" +# *Short* size names. These can be used as suffixes +t MSG_020 "bytes" +t MSG_021 "KB" +t MSG_022 "MB" +t MSG_023 "GB" +t MSG_024 "TB" +t MSG_025 "PB" +# *Long* size names, as they are displayed for the cluster size in the MS format dialog. +t MSG_026 "bytes" # Yes, this is a repeat from MSG_020 +t MSG_027 "kilobytes" +t MSG_028 "megabytes" +t MSG_029 "Default" +# The following gets appended to the file system, cluster size, etc. +t MSG_030 "%s (Default)" +t MSG_031 "%s partition scheme for BIOS computer" +t MSG_032 "%s partition scheme for UEFI computer" +t MSG_033 "%s partition scheme for BIOS or UEFI computers" +# Number of bad block check passes (singular for 1 pass, plural for 2 or more passes) +t MSG_034 "%d Pass" +t MSG_035 "%d Passes" +t MSG_036 "ISO Image" +t MSG_037 "Application" +t MSG_038 "Abort" +t MSG_039 "Launch" +t MSG_040 "Download" +t MSG_041 "Operation cancelled by the user" +t MSG_042 "Error" +t MSG_043 "Error: %s" +t MSG_044 "File download" +t MSG_045 "USB Storage Device (Generic)" +t MSG_046 "%s (Disk %d)" +t MSG_047 "%s (%c:)" +t MSG_048 "Rufus - Flushing buffers" +t MSG_049 "Rufus - Cancellation" + +# Error messages +t MSG_050 "Success." +t MSG_051 "Undetermined error while formatting." +t MSG_052 "Cannot use the selected file system for this media." +t MSG_053 "Access to the device is denied." +t MSG_054 "Media is write protected." +t MSG_055 "The device is in use by another process. " + "Please close any other process that may be accessing the device." +t MSG_056 "Quick format is not available for this device." +t MSG_057 "The volume label is invalid." +t MSG_058 "The device handle is invalid." +t MSG_059 "The selected cluster size is not valid for this device." +t MSG_060 "The volume size is invalid." +t MSG_061 "Please insert a media in drive." +t MSG_062 "An unsupported command was received." +t MSG_063 "Memory allocation error." +t MSG_064 "Read error." +t MSG_065 "Write error." +t MSG_066 "Installation failure" +t MSG_067 "Could not open media. It may be in use by another process. " + "Please re-plug the media and try again." +t MSG_068 "Error while partitioning drive." +t MSG_069 "Could not copy files to target drive." +t MSG_070 "Cancelled by user." +t MSG_071 "Unable to create formatting thread." +t MSG_072 "Bad blocks check didn't complete." +t MSG_073 "ISO image scan failure." +t MSG_074 "ISO image extraction failure." +t MSG_075 "Unable to remount volume." +t MSG_076 "Unable to patch/setup files for boot." +t MSG_077 "Unable to assign a drive letter." +t MSG_078 "Can't mount GUID volume." + +t MSG_080 "Rufus detected that Windows is still flushing its internal buffers onto the USB device.\n\n" + "Depending on the speed of your USB device, this operation may take a long time to complete, " + "especially for large files.\n\nWe recommend that you let Windows finish, to avoid corruption. " + "But if you grow tired of waiting, you can just unplug the device..." +t MSG_081 "Unsupported ISO" +t MSG_082 "This version of Rufus only supports bootable ISOs based on bootmgr/WinPE, isolinux or EFI.\n" + "This ISO doesn't appear to use either..." +t MSG_083 "Replace %s?" +t MSG_084 "This ISO image seems to use an obsolete version of '%s'.\n" + "Boot menus may not display properly because of this.\n\n" + "A newer version can be downloaded by Rufus to fix this issue:\n" + "- Choose 'Yes' to connect to the internet and download the file\n" + "- Choose 'No' to leave the existing ISO file unmodified\n" + "If you don't know what to do, you should select 'Yes'.\n\n" + "Note: The new file will be downloaded in the current directory and once a " + "'%s' exists there, it will be reused automatically." +t MSG_085 "Downloading %s" +t MSG_086 "No ISO image selected" +# The content between the quotes below (\"Create a bootable disk\") should match +# the beginning of the IDC_BOOT text +t MSG_087 "Please click on the disc button to select a bootable ISO, " + "or uncheck the \"Create a bootable disk...\" checkbox." +t MSG_088 "ISO too big" +t MSG_089 "This ISO image is too big for the selected target." +t MSG_090 "Unsupported ISO" +t MSG_091 "When using UEFI Target Type, only EFI bootable ISO images are supported. " + "Please select an EFI bootable ISO or set the Target Type to BIOS." +t MSG_092 "Unsupported filesystem" +t MSG_093 "When using UEFI Target Type, only FAT/FAT32 is supported. " + "Please select FAT/FAT32 as the File system or set the Target Type to BIOS." +t MSG_094 "Non UEFI compatible ISO" +t MSG_095 "This ISO image contains a file larger than 4 GB and cannot be used to create an EFI bootable USB.\n" + "This is a limitation of UEFI/FAT32, not Rufus." +t MSG_096 "Only FAT/FAT32 is supported for this type of ISO. Please select FAT/FAT32 as the File system." +t MSG_097 "Only 'bootmgr' or 'WinPE' based ISO images can currently be used with NTFS." +t MSG_098 "FAT/FAT32 can only be used for isolinux based ISO images or when the Target Type is UEFI." +t MSG_099 "Filesystem limitation" +t MSG_100 "This iso image contains a file larger than 4GB file, which is more than the " + "maximum size allowed for a FAT or FAT32 file system." +t MSG_101 "Missing WIM support" +t MSG_102 "Your platform cannot extract files from WIM archives. WIM extraction " + "is required to create EFI bootable Windows 7 and Windows Vista USB drives. You can fix that " + "by installing a recent version of 7-Zip.\nDo you want to visit the 7-zip download page?" +t MSG_103 "Download %s?" +t MSG_104 "Syslinux v5.0 or later requires a '%s' file to be installed.\n" + "Because this file is more than 100 KB in size, and always present on Syslinux v5+ ISO images, " + "it is not embedded in Rufus.\n\nRufus can download the missing file for you:\n" + "- Select 'Yes' to connect to the internet and download the file\n" + "- Select 'No' if you want to manually copy this file on the drive later\n\n" + "Note: The file will be downloaded in the current directory and once a " + "'%s' exists there, it will be reused automatically.\n" +t MSG_105 "Cancelling may leave the device in an UNUSABLE state.\n" + "If you are sure you want to cancel, click YES. Otherwise, click NO." +t MSG_106 "Please select folder" +t MSG_107 "All files" +t MSG_108 "Rufus log" +t MSG_109 "0x%02X (Disk %d)" + +# Tootips +# Partition Scheme and Target Type +t MSG_150 "Usually the safest choice. If you have an UEFI computer and want to install " + "an OS in EFI mode however, you should select one of the options below" +t MSG_151 "Use this if you want to install an OS in EFI mode, but need to access " + "the USB content from Windows XP" +t MSG_152 "The preferred option to install an OS in EFI mode and when " + "USB access is not required for Windows XP" +t MSG_153 "Test pattern: 0x%02X" +t MSG_154 "Test pattern: 0x%02X, 0x%02X" +t MSG_155 "Test pattern: 0x%02X, 0x%02X, 0x%02X" +t MSG_156 "Test pattern: 0x%02X, 0x%02X, 0x%02X, 0x%02X" +t MSG_157 "Sets the target filesystem" +t MSG_158 "Minimum size that a block of data will occupy in the filesystem" +t MSG_159 "Use this field to set the drive label\nInternational characters are accepted" +t MSG_160 "Toggle advanced options" +t MSG_161 "Check the device for bad blocks using a test pattern" +t MSG_162 "Uncheck this box to use the \"slow\" format method" +t MSG_163 "Check this box to make the USB drive bootable" +t MSG_164 "Method that will be used to make the drive bootable" +t MSG_165 "Click to select an ISO..." +t MSG_166 "Check this box to allow the display of international labels " + "and set a device icon (creates an autorun.inf)" +t MSG_167 "Install an MBR that allows boot selection and can masquerade the BIOS USB drive ID" +t MSG_168 "Try to masquerade first bootable USB drive (usually 0x80) as a different disk.\n" + "This should only be necessary if you install Windows XP and have more than one disk" +t MSG_169 "Create an extra hidden partition and try to align partitions boundaries.\n" + "This can improve boot detection for older BIOSes" +t MSG_170 "Enable detection for disks not normally detected by Rufus. USE AT YOUR OWN RISKS!!!" +t MSG_171 "Start the formatting operation.\nThis will DESTROY any data on the target!" +t MSG_172 "Licensing information and credits" +t MSG_173 "Click to select..." +# The following will appear in the about dialog +t MSG_174 "Rufus - The Reliable USB Formatting Utility" +t MSG_175 "Version %d.%d.%d (Build %d)" +t MSG_176 "" +t MSG_177 "Report bugs or request enhancements at:" +t MSG_178 "Additional Copyrights:" +t MSG_179 "Update Policy:" +t MSG_180 "If you choose to allow this program to check for application updates, " + "you agree that the following information may be collected on our server(s):" +t MSG_181 "Your operating system's architecture and version" +t MSG_182 "The version of the application you use" +t MSG_183 "Your IP address" +t MSG_184 "For the purpose of generating private usage statistics, we may keep the information collected, " + "\\b for at most a year\\b0 . However, we will not willingly disclose any of this individual data to third parties." +t MSG_185 "Update Process:" +t MSG_186 "Rufus does not install or run background services, therefore update checks are performed only when the main application is running.\\line\n" + "Internet access is of course required when checking for updates." + +# Status messages - these messages will appear on the status bar +t MSG_201 "Cancelling - Please wait..." +t MSG_202 "Scanning ISO image..." +t MSG_203 "Failed to scan ISO image" +# Parameter: the name of an obsolete Syslinux .c32 module. eg: "Obsolete vesamenu.c32 detected" +t MSG_204 "Obsolete %s detected" +# Display the name of the ISO selected. eg: "Using ISO: en_win7_x64_sp1.iso" +t MSG_205 "Using ISO: %s" +# Typically "Missing ldlinux.c32 file" +t MSG_206 "Missing %s file" +# Same message, once for singular and plural ("1 device found", "2 devices found") +t MSG_208 "%d device found" +t MSG_209 "%d devices found" +t MSG_210 "DONE." +t MSG_211 "Cancelled." +t MSG_212 "FAILED." +# Used when a new update has been downloaded and lauched +t MSG_213 "Launching new application..." +t MSG_214 "Failed to launch new application" +# Open/Save file +t MSG_215 "Opened %s" +t MSG_216 "Saved %s" +# Formatting status (make sure you use a double % to print the percent sign) +t MSG_217 "Formatting: %0.1f%% completed" +t MSG_218 "Creating file system: Task %d/%d completed" +t MSG_219 "NTFS Fixup: %d%% completed" +t MSG_221 "Setting Label (This may take while)..." +# Parameter: the file system. eg. "Formatting (NTFS)..." +t MSG_222 "Formatting (%s)..." +t MSG_223 "NTFS Fixup (Checkdisk)..." +t MSG_224 "Clearing MBR/PBR/GPT structures..." +t MSG_225 "Requesting disk access..." +t MSG_226 "Analyzing existing boot records..." +t MSG_227 "Closing existing volume..." +t MSG_228 "Writing master boot record..." +t MSG_229 "Writing partition boot record..." +t MSG_230 "Copying DOS files..." +t MSG_231 "Copying ISO files..." +t MSG_232 "Win7 EFI boot setup (this may take a while)..." +t MSG_233 "Finalizing, please wait..." +# Takes the Syslinux version as paramete. eg. "Installing Syslinux v5..." +t MSG_234 "Installing Syslinux v%d..." +# Bad blocks status. eg: "Bad Blocks: PASS 1/2 - 12.34% (0/0/1 errors)" +t MSG_235 "Bad Blocks: PASS %d/%d - %0.2f%% (%d/%d/%d errors)" +t MSG_236 "Bad Blocks: Testing with random pattern" +t MSG_237 "Bad Blocks: Testing with pattern 0x%02X" +# eg. "Partitioning (MBR)..." +t MSG_238 "Partitioning (%s)..." +t MSG_239 "Deleting partitions..." +t MSG_240 "Downloading %s: Connecting..." +t MSG_241 "Downloading: %0.1f%%" +t MSG_242 "Failed to download file." +t MSG_243 "Checking for Rufus updates..." +t MSG_244 "Updates: Unable to connect to the internet" +t MSG_245 "Updates: Unable to acces version data" +t MSG_246 "A new version of Rufus is available!" +t MSG_247 "No new version of Rufus was found" +t MSG_248 "Application registry keys successfully deleted" +t MSG_249 "Failed to delete application registry keys" +# eg. "Fixed disk detection enabled" "ISO size check disabled" +t MSG_250 "%s enabled" +t MSG_251 "%s disabled" +t MSG_252 "Size checks" +t MSG_253 "Fixed disks detection" +t MSG_254 "Force large FAT32 formatting" +t MSG_255 "NoDriveTypeAutorun will be deleted on exit" +t MSG_256 "Fake drive detection" +t MSG_257 "Joliet support" +t MSG_258 "Rock Ridge support" + +################################################################################ +l "fr_FR" "French" 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c +g IDD_DIALOG +t IDS_DEVICE_TXT "Periphérique" +t IDS_PARTITION_TYPE_TXT "Type de partition et système de destination" +t IDS_FILESYSTEM_TXT "Système de fichiers" +t IDS_CLUSTERSIZE_TXT "Taille de clusters" +t IDS_LABEL_TXT "Nouveau label" +t IDS_FORMAT_OPTIONS_GRP "Options de Formattage " +t IDC_BADBLOCKS "Vérification de mauvais blocs:" +s IDC_BADBLOCKS +10,0 +m IDC_NBPASSES +5,0 +t IDC_QUICKFORMAT "Formattage rapide" +t IDC_BOOT "Disque de démarrage utilisant:" +s IDC_BOOT +5,0 +m IDC_BOOTTYPE +5,0 +m IDC_SELECT_ISO +3,0 +t IDC_SET_ICON "Ajouter un label étendu et une icône" +m IDC_ADVANCED +36,0 +t IDC_ABOUT "A propos..." +t IDCANCEL "Fermer" +t IDC_START "Démarrer" +t IDS_ADVANCED_OPTIONS_GRP "Options avancées" +t IDC_ENABLE_FIXED_DISKS "Lister les disques fixes ou non partitionés" +t IDC_EXTRA_PARTITION "Options de compatibilité avec anciens BIOS" +t IDC_RUFUS_MBR "Ajout du MBR Rufus, ID BIOS:" +m IDC_DISK_ID +5,0 +s IDC_DISK_ID -2,0 + +g IDD_ABOUTBOX +t IDD_ABOUTBOX "A propos de Rufus" +t IDC_ABOUT_LICENSE "License" +t IDC_ABOUT_UPDATES "Mises à jour" + +g IDD_LICENSE +t IDD_LICENSE "License Rufus" + +g IDD_NOTIFICATION +t IDC_MORE_INFO "Plus d'info..." +t IDYES "Oui" +t IDNO "Non" + +g IDD_LOG +t IDC_LOG_CLEAR "Effacer" +t IDC_LOG_SAVE "Enregistrer" +t IDCANCEL "Fermer" + +g IDD_UPDATE_POLICY +s IDD_UPDATE_POLICY +30,0 +t IDD_UPDATE_POLICY "Paramètres de mises à jour" +s IDC_POLICY +30,0 +t IDS_UPDATE_SETTINGS_GRP "Options" +s IDS_UPDATE_SETTINGS_GRP +20,0 +t IDS_UPDATE_FREQUENCY_TXT "Recherche mises à jour:" +s IDS_UPDATE_FREQUENCY_TXT -3,0 +t IDS_INCLUDE_BETAS_TXT "Inclure les bétas:" +m IDC_UPDATE_FREQUENCY -3,0 +m IDC_INCLUDE_BETAS -3,0 +s IDC_UPDATE_FREQUENCY +25,0 +m IDS_CHECK_NOW_GRP 20,0 +s IDS_CHECK_NOW_GRP +10,0 +t IDC_CHECK_NOW "Chercher maintenant" +m IDC_CHECK_NOW 9,0 +s IDC_CHECK_NOW +31,0 +t IDCANCEL "Fermer" +m IDCANCEL 9,0 + +g IDD_NEW_VERSION +t IDD_NEW_VERSION "Mise à jour de Rufus" +t IDS_NEW_VERSION_AVAIL_TXT "Une nouvelle version est disponible. Veuillez télécharger la nouvelle version !" +t IDC_WEBSITE "Cliquez ici pour aller sur le site de Rufus" +t IDS_NEW_VERSION_NOTES_GRP "Notes relatives à cette version" +t IDS_NEW_VERSION_DOWNLOAD_GRP "Téléchargement" +t IDC_DOWNLOAD ""Télécharger"" +t IDCANCEL "Fermer" + +g IDD_ISO_EXTRACT +t IDD_ISO_EXTRACT "Copie des fichier ISO..." +t IDC_ISO_FILENAME "Ouverture de l'image - veuillez patienter..." +t IDC_ISO_ABORT "Annuler" + +g IDD_MESSAGES +t MSG_001 "Autre instance detectée" +t MSG_002 "Une autre instance de Rufus est en cours d'exécution.\n" + "Veuillez fermer la première instance avant d'en lancer une seconde." +t MSG_003 "ATTENTION: TOUTES LES DONNEES DU VOLUME '%s' VONT ETRE EFFACEES.\n" + "Pour continuer cette operation, cliquez sur OK.\nPour quitter cliquez sur ANNULER." +t MSG_004 "Mises à jour" +t MSG_005 "Voulez-vous authoriser Rufus à chercher des mises à jour en ligne?" +t MSG_006 "Fermer" +t MSG_007 "Annuler" +t MSG_008 "Oui" +t MSG_009 "Non" +t MSG_010 "Blocs défectueux détectés" +t MSG_011 "Vérification complète: %u bloc(s) défectueux détecté(s)\n" + " %d erreur(s) de lecture\n %d erreur(s) d'écriture\n %d erreur(s) de corruption\n" +t MSG_012 "%s\nUn rapport plus détaillé peut être obtenu à:\n%s" +t MSG_013 "Jamais" +t MSG_014 "Quotidienne" +t MSG_015 "Hebdomadaire" +t MSG_016 "Mensuelle" +t MSG_017 "Personalisée" +t MSG_018 "Votre version: %d.%d.%d (Build %d)" +t MSG_019 "Dernière version: %d.%d.%d (Build %d)" +t MSG_020 "octets" +t MSG_021 "Ko" +t MSG_022 "Mo" +t MSG_023 "Go" +t MSG_024 "To" +t MSG_025 "Po" +t MSG_026 "octets" +t MSG_027 "kilo-octets" +t MSG_028 "mega-octets" +t MSG_029 "Défaut" +t MSG_030 "%s (Défaut)" +t MSG_031 "Type de partition %s pour ordinateur BIOS" +t MSG_032 "Type de partition %s pour ordinateur UEFI" +t MSG_033 "Type de partition %s pour ordinateur BIOS ou UEFI" +t MSG_034 "%d passe" +t MSG_035 "%d passes" +t MSG_036 "Image ISO" +t MSG_037 "Application" +t MSG_038 "Annuler" +t MSG_039 "Lancer" +t MSG_040 "Télécharger" +t MSG_041 "Operation annulée par l'utilisateur" +t MSG_042 "Erreur" +t MSG_043 "Erreur: %s" +t MSG_044 "Téléchargement de fichier" +t MSG_045 "Pérpih. de stockage USB (Générique)" +t MSG_046 "%s (Disque %d)" +t MSG_047 "%s (%c:)" +t MSG_048 "Rufus - Flush de la mémoire tampon" +t MSG_049 "Rufus - Annulation" + +# Error messages +t MSG_050 "Opération réussie." +t MSG_051 "Erreur indéterminéee lors du formatage." +t MSG_052 "Ce système de fichiers ne peut pas être utilisé ici." +t MSG_053 "L'accès au périphérique est refusé." +t MSG_054 "Le périphérique est protegé en écriture." +t MSG_055 "Le périphérique est en cours d'utilisation par une autre application. " + "Veuillez fermer toute autre application succeptible d'accéder au périphérique." +t MSG_056 "Le formatage rapide n'est pas disponible pour ce périphérique." +t MSG_057 "Le nom de volume est invalide." +t MSG_058 "Le handle de périphérique est invalide." +t MSG_059 "Cette taille de cluster n'est pas appliquable ici." +t MSG_060 "La taille du volume est invalide." +t MSG_061 "Veuillez insérer un média dans le lecteur." +t MSG_062 "Commande non supportée." +t MSG_063 "Erreur d'allocation mémoire." +t MSG_064 "Erreur de lecture." +t MSG_065 "Erreur d'écriture." +t MSG_066 "L'installation a échoué" +t MSG_067 "Impossible d'accéder au média. Il peut être en cours d'utilisation par une autre application. " + "Essayer de déconnecter le média et essayez à nouveau." +t MSG_068 "Erreur de partitionement." +t MSG_069 "Impossible de copier les fichiers sur le périphérique de detination." +t MSG_070 "Opération annulée par l'utilisateur." +t MSG_071 "Impossible de créer le thread de formattage." +t MSG_072 "La vérification de blocs défectueux a été interrompue." +t MSG_073 "Echec d'analyse de l'image ISO." +t MSG_074 "Echec d'extraction de l'image ISO." +t MSG_075 "Echec lors du remontage du volume." +t MSG_076 "Echec de modification des fichiers de démarrage." +t MSG_077 "Echec d'assignation d'une lettre de volume." +t MSG_078 "Impossible de monter le volume GUID." + +t MSG_080 "Rufus a detecté que Windows est en train de finir de vider la mémoire tampon.\n\n" + "En fonction de la vitesse de votre périphérique, cette opération peut prendre beaucoup de temps, " + "surtout s'il s'agit d'un fichier volumineux.\n\nNous recommandons d'attendre que Windows " + "complète cette opération, afin d'éviter la corruption du périphérique. Mais si jamais cela prend " + "trop de temps, vous pouvez toujours essayer de déconnecter le média..." +t MSG_081 "Image ISO non supportée" +t MSG_082 "Cette version de Rufus supporte seulement les ISOs démarrables qui utilisent bootmgr/WinPE, isolinux ou EFI.\n" + "Cette image ISO ne semble pas utiliser une de ces options..." +t MSG_083 "Remplacer %s?" +t MSG_084 "Cette image ISO utilise une version obsolète du fichier '%s'.\n" + "A cause de cela, les menus de démarrage peuvent de pas fonctionner.\n\n" + "Une nouvelle version du fichier peut être téléchargée par Rufus pour addresser ce problème:\n" + "- Choisissez 'Oui' pour télécharger le fichier depuis Internet\n" + "- Choisissez 'Non' pour garder le fichier de l'image ISO\n" + "Si vous ne savez pas quoi faire, sélectionnez 'Oui'.\n\n" + "Note: Le nouveau fichier est téléchargé dans le répertoire courrant. Une fois qu'un fichier" + "'%s' existe à cet endroit, il sera réutilisé automatiquement." +t MSG_085 "Téléchargement de %s" +t MSG_086 "Aucune image ISO sélectionnée" +t MSG_087 "Veuillez cliquer sur le bouton avec un disque pour choisir une image ISO démarrable " + "ou décochez l'option \"Disque de démarrage...\"." +t MSG_088 "Image ISO trop large" +t MSG_089 "Cette ISO image est trop large pour le périphérique sélectionné." +t MSG_090 "Image ISO on supportée" +t MSG_091 "Quand UEFI est séelectionné, seules les images ISO basées sur EFI sont supportées. " + "Veuillez sélectionner une image ISO démarrable avec EFI ou sélectionner BIOS pour le système de destination." +t MSG_092 "Système de fichiers non supporté" +t MSG_093 "Quand UEFI est séelectionné, seul le système de fichiers FAT/FAT32 est supporté. " + "Veuillez sélectionner FAT/FAT32 comme système de fichiers ou sélectionner BIOS pour le système de destination." +t MSG_094 "Image ISO incompatible avec UEFI" +t MSG_095 "Cette image ISO contient un fichier de plus de 4 Go et ne peut pas être utilisée pour créer un USB démarrable par UEFI.\n" + "Ceci est une limitation de UEFI/FAT32, pas de Rufus." +t MSG_096 "Seul FAT/FAT32 est supporté avec ce type d'image ISO. Veuillez sélectionner FAT/FAT32 pour le système de fichiers." +t MSG_097 "Seules les images ISO utilisant 'bootmgr' ou 'WinPE' peuvent être utilisées avec NTFS." +t MSG_098 "FAT/FAT32 peut seulement être utilisé pour les images ISO utilisant 'isolinux' ou lorsque que le système de destination est UEFI." +t MSG_099 "Limitation du système de fichiers" +t MSG_100 "Cette image ISO contient un fichier de plus de 4 Go, ce qui est plus que la taille maximum " + "supportée par le système de fichiers FAT ou FAT32." +t MSG_101 "Support pour archives WIM non disponible" +t MSG_102 "Votre plateforme ne peut pas extraire les fichiers depuis les archives WIM. L'extraction de données WIM " + "est nécéssaire pour créer des médias USB démarrable avec EFI pour Windows 7/8 ou Windows Vista. Vous pouvez addresser " + "ce problème en téléchargeant une version récente de l'utilitaire 7-Zip.\nVoulez-vous visiter la page de téléchargements de 7-zip?" +t MSG_103 "Télécharger %s?" +t MSG_104 "Syslinux v5.0 ou plus récent requiert l'installtion d'un fichier '%s'.\n" + "Puisque ce fichier fait plus de 100 Ko et est toujours présent sur les images ISO à base de Syslinux v5+, " + "il n'est pas inclus dans l'application.\n\nRufus peut télécharger ce fichier pour vous:\n" + "- Choisissez 'Oui' pour télécharger le fichier depuis Internet\n" + "- Choisissez 'Non' si vous compter copier ce fichier manuellement\n" + "Note: Ce fichier est téléchargé dans le répertoire courrant. Une fois qu'un fichier" + "'%s' existe à cet endroit, il sera réutilisé automatiquement." +t MSG_105 "Annuler peut laisser le périphérique dans un état inutilisable.\n" + "Si vous êtes sûr de vouloir annuler, sélectionnez OUI. Sinon, sélectionnez NON." +t MSG_106 "Sélection de répertoire" +t MSG_107 "Tous les fichiers" +t MSG_108 "Log Rufus" +t MSG_109 "0x%02X (disque %d)" + +# Tootips +t MSG_150 "Choix le plus sûr. Si toutefois vous possédez un ordinateur à base de UEFI et voulez installer " + "un Système d’exploitation en mode EFI, vous devriez plutôt sélectionner l’une des options ci-dessous" +t MSG_151 "Utilisez cette options si vous comptez installer un Système d’exploitation en mode EFI " + "et avez aussi besoin d’accéder au contenu du média sous Windows XP" +t MSG_152 "Option préférée pour installer un Système d’exploitation en mode EFI, " + "quand l’accès au média depuis Windows XP n’est pas nécessaire" +t MSG_153 "Motif de test: 0x%02X" +t MSG_154 "Motif de test: 0x%02X, 0x%02X" +t MSG_155 "Motif de test: 0x%02X, 0x%02X, 0x%02X" +t MSG_156 "Motif de test: 0x%02X, 0x%02X, 0x%02X, 0x%02X" +t MSG_157 "Sélectionne le système de fichiers" +t MSG_158 "La taille minimum qu’un bloc de données occupera sur le système de fichiers" +t MSG_159 "Utilisez ce champ pour mettre à jour le nom du volume\n" + "Les caractères étendus et les accents sont acceptés " +t MSG_160 "Affiche/Cache les options avancées " +t MSG_161 "Détecte la présence de blocs défectueux en utilisant un motif de test" +t MSG_162 "Décochez cette case pour utiliser la méthode de formatage \"lente\" " +t MSG_163 "Cochez cette case pour rendre le périphérique démarrable" +t MSG_164 "Méthode à utiliser pour rendre le périphérique démarrable " +t MSG_165 "Cliquez ici pour sélectionner une image ISO..." +t MSG_166 "Cochez cette case pour permettre l’affichage des caractères étendus/internationaux " + "et ajouter une icône (créé un fichier autorun.inf)" +t MSG_167 "Installe un MBR permettant la sélection du périphérique de démarrage. Peut aussi " + "camoufler l’ID de disque pour le BIOS " +t MSG_168 "Camoufle le premier disque USB démarrable (généralement 0x80) sous une ID différente.\n" + "Changez cette option si vous installez Windows XP avec plus d’un disque dur" +t MSG_169 "Créé une petite partition supplémentaire et essaye d’aligner les partitions.\n" + "Peut améliorer la détection USB pour les vieux BIOS" +t MSG_170 "Active la détection de disque non normalement listés par Rufus. UTILISEZ A VOS PROPRES RISQUES !!! " +t MSG_171 "Lance le formatage. DETRUIT toutes les données existantes sur la cible !" +t MSG_172 "Licence d’utilisation et remerciements" +t MSG_173 "Cliquez pour sélectionner..." +t MSG_174 "Rufus - The Reliable USB Formatting Utility" +t MSG_175 "Version %d.%d.%d (Build %d)" +t MSG_176 "Traduction Française: Pete Batard" +t MSG_177 "Soumettre un bug ou une demande d'amélioration à:" +t MSG_178 "Copyrights supplémentaires:" +t MSG_179 "Politique de mises à jour:" +t MSG_180 "Si vous autorisez ce programme à chercher les mises à jour, vous acceptez " + "que les informations suivantes peuvent être collectées sur nos serveurs:" +t MSG_181 "L’architecture de votre système d’exploitation ainsi que sa version" +t MSG_182 "La version de l’application que vous utilisez" +t MSG_183 "Votre adresse IP" +t MSG_184 "Afin de générer des statistiques d’utilisation privées, il se peut que nous gardions " + "les informations ainsi obtenues \\b au plus un an\\b0 . A moins d’y être contraint par la loi, " + "nous nous engageons aussi à ne pas diffuser ces informations à de tierce parties." +t MSG_185 "Processus de mise à jour:" +t MSG_186 "Aucun service ou tâche de fond ne sont installés ou lancés par Rufus. Cela veut dire que les " + "test de mises à jour interviennent seulement lorsque l’application principale s'exécute.\\line\n" + "Bien entendu, un accès à internet est requis pour vérifier la disponibilité des mises à jour." + +# Status messages +t MSG_201 "Annulation - Veuillez patienter..." +t MSG_202 "Analyse de l'image ISO..." +t MSG_203 "Echec d'analyse de l'image ISO" +t MSG_204 "Fichier %s obsolète detecté" +t MSG_205 "ISO utilisée: %s" +t MSG_206 "Fichier %s manquant" +t MSG_208 "%d périphérique détecté" +t MSG_209 "%d périphériques détectés" +t MSG_210 "Opération terminée." +t MSG_211 "Opération annulée." +t MSG_212 "ECHEC." +t MSG_213 "Lancement de la nouvelle application..." +t MSG_214 "Echec de lancement de l'application" +t MSG_215 "%s ouvert" +t MSG_216 "%s sauvegardé" +t MSG_217 "Formatage: %0.1f%% complet" +t MSG_218 "Création du système de fichiers: Tâche %d/%d complète" +t MSG_219 "Finalisation NTFS: %d%% complète" +t MSG_221 "Ecriture du label (peut prendre du temps)..." +t MSG_222 "Formatage (%s)..." +t MSG_223 "Finalisation NTFS (Checkdisk)..." +t MSG_224 "Effacement des structures MBR/PBR/GPT..." +t MSG_225 "Requête d'accès disque..." +t MSG_226 "Analyse des structures de boot existantes..." +t MSG_227 "Fermeture des volumes existants..." +t MSG_228 "Ecriture du MBR..." +t MSG_229 "Ecriture du PBR..." +t MSG_230 "Copie des fichiers DOS..." +t MSG_231 "Copie des fichiers ISO..." +t MSG_232 "Ecriture boot Win7 EFI (peut prendre du temps)..." +t MSG_233 "Finalisation, veuillez patienter..." +t MSG_234 "Installation de Syslinux v%d..." +t MSG_235 "Défauts: PASSE %d/%d - %0.2f%% (%d/%d/%d erreurs)" +t MSG_236 "Défauts: Test avec motif aléatoire" +t MSG_237 "Défauts: Test avec motif 0x%02X" +t MSG_238 "Partitionage (%s)..." +t MSG_239 "Effaçement des partitions..." +t MSG_240 "Télechargement de %s: Connection..." +t MSG_241 "Télechargement: %0.1f%%" +t MSG_242 "Echec de télechargement du fichier" +t MSG_243 "Recherche des mises à jour..." +t MSG_244 "MAJ: Impossible de se connecter" +t MSG_245 "MAJ: Pas d'accès aux données de mises à jour" +t MSG_246 "Une nouvelle version de Rufus est disponible !" +t MSG_247 "Pas de mise à jour" +t MSG_248 "Clés de registre supprimées" +t MSG_249 "Echec de suppression des clés registres" +t MSG_250 "%s activé" +t MSG_251 "%s désactivé" +t MSG_252 "Tests de dépassement de taille" +t MSG_253 "Détection de disques fixes" +t MSG_254 "Force 'large FAT32'" +t MSG_255 "NoDriveTypeAutorun sera effacé en sortie" +t MSG_256 "Test de contrefaçons" +t MSG_257 "Support Joliet" +t MSG_258 "Support Rock Ridge" + +################################################################################ +l "zh_CN" "Chinese (Traditional)" 0x0404, 0x0804, 0x0c04, 0x1004, 0x1404 +g IDD_DIALOG +t IDS_DEVICE_TXT "设备" +t IDS_PARTITION_TYPE_TXT "分区计划和目标系统类型" +t IDS_FILESYSTEM_TXT "文件系统" +t IDS_CLUSTERSIZE_TXT "簇的大小" +t IDS_LABEL_TXT "新卷标" +t IDS_FORMAT_OPTIONS_GRP "格式选项 " +t IDC_BADBLOCKS "检查设备的坏块:" +t IDC_QUICKFORMAT "快速格式化" +t IDC_BOOT "创建一个可启动的磁盘使用:" +s IDC_BOOT +10,0 +t IDC_SET_ICON "创建扩展标签和图标文件" +m IDC_ADVANCED -24,0 +m IDC_NBPASSES 8,0 +m IDC_BOOTTYPE 8,0 +m IDC_SELECT_ISO 6,0 +t IDC_ABOUT "关于..." +t IDC_LOG "日志" +m IDC_LOG -5,0 +s IDC_LOG +5,0 +t IDCANCEL "关闭" +t IDC_START "开始" +t IDS_ADVANCED_OPTIONS_GRP "高级选项" +t IDC_ENABLE_FIXED_DISKS "列表固定(非flash)或USB磁盘分区" +t IDC_EXTRA_PARTITION "添加修复旧的BIOS(额外的分区,校准等等)" +t IDC_RUFUS_MBR "使用 Rufus MBR BIOS ID:" + +g IDD_ABOUTBOX +t IDD_ABOUTBOX "关于 Rufus" +t IDC_ABOUT_LICENSE "许可证" +t IDC_ABOUT_UPDATES "更新" +t IDOK "确定" + +g IDD_LICENSE +t IDD_LICENSE "Rufus 许可证" +t IDOK "取消" + +g IDD_NOTIFICATION +t IDD_NOTIFICATION "更新方案和设置" +t IDC_MORE_INFO "更多信息" +t IDYES "是" +t IDNO "否" + +g IDD_LOG +t IDD_LOG "日志" +t IDC_LOG_CLEAR "清除日志" +t IDC_LOG_SAVE "保存日志" +t IDCANCEL "关闭日志" + +g IDD_LICENSE +t IDOK "取消" + +g IDD_UPDATE_POLICY +t IDD_UPDATE_POLICY "更新方案和设置" +t IDS_UPDATE_SETTINGS_GRP "设置" +t IDS_UPDATE_FREQUENCY_TXT "检查更新:" +t IDS_INCLUDE_BETAS_TXT "包括测试版本:" +t IDC_CHECK_NOW "立即检查" +t IDCANCEL "取消" + +g IDD_NEW_VERSION +t IDD_NEW_VERSION "检查更新 - Rufus" +t IDS_NEW_VERSION_AVAIL_TXT "更新的版本可用。请下载最新版本!" +t IDC_WEBSITE "点击这里进入网站" +t IDS_NEW_VERSION_NOTES_GRP "发行说明" +t IDS_NEW_VERSION_DOWNLOAD_GRP "下载" +t IDC_DOWNLOAD "下载" +t IDCANCEL "取消" + +g IDD_ISO_EXTRACT +t IDD_ISO_EXTRACT "复制ISO文件..." +t IDC_ISO_FILENAME "打开ISO映像 - 请稍候..." +t IDC_ISO_ABORT "取消" + +g IDD_MESSAGES +t MSG_004 "更新方案和设置" +t MSG_005 "你要允許此應用程序檢查更新?" +t MSG_006 "关闭" +t MSG_007 "撤消" diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj index a47b2a1f..f19850d6 100644 --- a/src/.msvc/rufus.vcxproj +++ b/src/.msvc/rufus.vcxproj @@ -87,6 +87,7 @@ ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true + false setupapi.lib;comctl32.lib;wininet.lib;%(AdditionalDependencies) @@ -113,6 +114,7 @@ ProgramDatabase CompileAsC true + false setupapi.lib;comctl32.lib;wininet.lib;%(AdditionalDependencies) @@ -135,6 +137,7 @@ ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true + false setupapi.lib;comctl32.lib;wininet.lib;%(AdditionalDependencies) @@ -160,6 +163,7 @@ ..\msvc-missing;..\ms-sys\inc;..\syslinux\libinstaller;..\syslinux\libfat;..\libcdio;..\getopt;%(AdditionalIncludeDirectories) CompileAsC true + false setupapi.lib;comctl32.lib;wininet.lib;%(AdditionalDependencies) @@ -181,6 +185,7 @@ + @@ -197,6 +202,8 @@ + + diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters index e77ebd51..f7d61035 100644 --- a/src/.msvc/rufus.vcxproj.filters +++ b/src/.msvc/rufus.vcxproj.filters @@ -60,6 +60,9 @@ Source Files + + Source Files + @@ -101,6 +104,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/src/.msvc/rufus_sources b/src/.msvc/rufus_sources index c359e75c..f95c1bcc 100644 --- a/src/.msvc/rufus_sources +++ b/src/.msvc/rufus_sources @@ -36,6 +36,7 @@ SOURCES=rufus.c \ stdlg.c \ icon.c \ parser.c \ + localization.c \ net.c \ iso.c \ dos.c \ diff --git a/src/Makefile.am b/src/Makefile.am index decd2f84..2fbb05e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ pkg_v_rc_0 = @echo " RC $@"; %_rc.o: %.rc $(pkg_v_rc)$(WINDRES) $(AM_RCFLAGS) -i $< -o $@ -rufus_SOURCES = drive.c icon.c parser.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c +rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ diff --git a/src/Makefile.in b/src/Makefile.in index 04bef641..46003ead 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -44,12 +44,13 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am_rufus_OBJECTS = rufus-drive.$(OBJEXT) rufus-icon.$(OBJEXT) \ - rufus-parser.$(OBJEXT) rufus-iso.$(OBJEXT) rufus-net.$(OBJEXT) \ - rufus-dos.$(OBJEXT) rufus-dos_locale.$(OBJEXT) \ - rufus-badblocks.$(OBJEXT) rufus-syslinux.$(OBJEXT) \ - rufus-vhd.$(OBJEXT) rufus-format.$(OBJEXT) \ - rufus-stdio.$(OBJEXT) rufus-stdfn.$(OBJEXT) \ - rufus-stdlg.$(OBJEXT) rufus-rufus.$(OBJEXT) + rufus-parser.$(OBJEXT) rufus-localization.$(OBJEXT) \ + rufus-iso.$(OBJEXT) rufus-net.$(OBJEXT) rufus-dos.$(OBJEXT) \ + rufus-dos_locale.$(OBJEXT) rufus-badblocks.$(OBJEXT) \ + rufus-syslinux.$(OBJEXT) rufus-vhd.$(OBJEXT) \ + rufus-format.$(OBJEXT) rufus-stdio.$(OBJEXT) \ + rufus-stdfn.$(OBJEXT) rufus-stdlg.$(OBJEXT) \ + rufus-rufus.$(OBJEXT) rufus_OBJECTS = $(am_rufus_OBJECTS) rufus_DEPENDENCIES = rufus_rc.o ms-sys/libmssys.a \ syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ @@ -184,7 +185,7 @@ SUBDIRS = ms-sys syslinux/libfat syslinux/libinstaller libcdio/iso9660 libcdio/u pkg_v_rc = $(pkg_v_rc_$(V)) pkg_v_rc_ = $(pkg_v_rc_$(AM_DEFAULT_VERBOSITY)) pkg_v_rc_0 = @echo " RC $@"; -rufus_SOURCES = drive.c icon.c parser.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c +rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ @@ -269,6 +270,14 @@ rufus-parser.obj: parser.c $(AM_V_CC) @AM_BACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-parser.obj `if test -f 'parser.c'; then $(CYGPATH_W) 'parser.c'; else $(CYGPATH_W) '$(srcdir)/parser.c'; fi` +rufus-localization.o: localization.c + $(AM_V_CC) @AM_BACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-localization.o `test -f 'localization.c' || echo '$(srcdir)/'`localization.c + +rufus-localization.obj: localization.c + $(AM_V_CC) @AM_BACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-localization.obj `if test -f 'localization.c'; then $(CYGPATH_W) 'localization.c'; else $(CYGPATH_W) '$(srcdir)/localization.c'; fi` + rufus-iso.o: iso.c $(AM_V_CC) @AM_BACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-iso.o `test -f 'iso.c' || echo '$(srcdir)/'`iso.c diff --git a/src/badblocks.c b/src/badblocks.c index b7d27334..dfc3807a 100644 --- a/src/badblocks.c +++ b/src/badblocks.c @@ -45,6 +45,8 @@ #include "badblocks.h" #include "file.h" #include "msapi_utf8.h" +#include "resource.h" +#include "localization.h" FILE* log_fd = NULL; static const char* abort_msg = "Too many bad blocks, aborting test\n"; @@ -326,12 +328,12 @@ static void print_status(void) percent = calc_percent((unsigned long) currently_testing, (unsigned long) num_blocks); percent = (percent/2.0f) + ((cur_op==OP_READ)? 50.0f : 0.0f); - PrintStatus(0, FALSE, "Bad Blocks: PASS %d/%d - %0.2f%% (%d/%d/%d errors)", + PrintStatus(0, FALSE, lmprintf(MSG_235, cur_pattern, nr_pattern, - percent, + percent, num_read_errors, num_write_errors, - num_corruption_errors); + num_corruption_errors)); UpdateProgress(OP_BADBLOCKS, (((cur_pattern-1)*100.0f) + percent) / nr_pattern); } @@ -357,7 +359,7 @@ static void pattern_fill(unsigned char *buffer, unsigned int pattern, for (ptr = buffer; ptr < buffer + n; ptr++) { (*ptr) = rand() % (1 << (8 * sizeof(char))); } - PrintStatus(3500, FALSE, "Bad Blocks: Testing with random pattern."); + PrintStatus(3500, FALSE, lmprintf(MSG_236)); } else { bpattern[0] = 0; for (i = 0; i < sizeof(bpattern); i++) { @@ -374,7 +376,7 @@ static void pattern_fill(unsigned char *buffer, unsigned int pattern, else i--; } - PrintStatus(3500, FALSE, "Bad Blocks: Testing with pattern 0x%02X.", bpattern[i]); + PrintStatus(3500, FALSE, lmprintf(MSG_237, bpattern[i])); cur_pattern++; } } @@ -427,7 +429,7 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, size_t blocks_at_once, int nb_passes) { unsigned char *buffer = NULL, *read_buffer; - const unsigned int pattern[] = {0xaa, 0x55, 0xff, 0x00}; + const unsigned int pattern[] = BADBLOCK_PATTERNS; int i, pat_idx; unsigned int bb_count = 0; blk_t got, tryout, recover_block = ~0, *blk_id; diff --git a/src/drive.c b/src/drive.c index 90368da8..dd44525e 100644 --- a/src/drive.c +++ b/src/drive.c @@ -30,6 +30,7 @@ #include "rufus.h" #include "resource.h" #include "sys_types.h" +#include "localization.h" /* * Globals @@ -625,7 +626,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m DWORD size; LONGLONG size_in_sectors; - PrintStatus(0, TRUE, "Partitioning (%s)...", PartitionTypeName[partition_style]); + PrintStatus(0, TRUE, lmprintf(MSG_238, PartitionTypeName[partition_style])); if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_EXTRA_PARTITION))) { // Go with the MS 1 MB wastage at the beginning... @@ -772,7 +773,7 @@ BOOL DeletePartitions(HANDLE hDrive) DWORD size; CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}}; - PrintStatus(0, TRUE, "Deleting partitions..."); + PrintStatus(0, TRUE, lmprintf(MSG_239)); size = sizeof(CreateDisk); r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, diff --git a/src/format.c b/src/format.c index dd639df7..9a713fcf 100644 --- a/src/format.c +++ b/src/format.c @@ -43,6 +43,7 @@ #include "file.h" #include "format.h" #include "badblocks.h" +#include "localization.h" /* * Globals @@ -68,16 +69,16 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, switch(Command) { case FCC_PROGRESS: percent = (DWORD*)pData; - PrintStatus(0, FALSE, "Formatting: %d%% completed.", *percent); + PrintStatus(0, FALSE, lmprintf(MSG_217, *percent)); UpdateProgress(OP_FORMAT, 1.0f * (*percent)); break; case FCC_STRUCTURE_PROGRESS: // No progress on quick format - PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", ++task_number, nb_steps[fs_index]); + PrintStatus(0, TRUE, lmprintf(MSG_218, ++task_number, nb_steps[fs_index])); format_percent += 100.0f / (1.0f * nb_steps[fs_index]); UpdateProgress(OP_CREATE_FS, format_percent); break; case FCC_DONE: - PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", nb_steps[fs_index], nb_steps[fs_index]); + PrintStatus(0, TRUE, lmprintf(MSG_218, nb_steps[fs_index], nb_steps[fs_index])); UpdateProgress(OP_CREATE_FS, 100.0f); if(*(BOOLEAN*)pData == FALSE) { uprintf("Error while formatting.\n"); @@ -152,7 +153,7 @@ static BOOLEAN __stdcall ChkdskCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DW case FCC_PROGRESS: case FCC_CHECKDISK_PROGRESS: percent = (DWORD*)pData; - PrintStatus(0, FALSE, "NTFS Fixup: %d%% completed.", *percent); + PrintStatus(0, FALSE, lmprintf(MSG_219, *percent)); break; case FCC_DONE: if(*(BOOLEAN*)pData == FALSE) { @@ -365,7 +366,8 @@ static BOOL FormatFAT32(DWORD DriveIndex) // Debug temp vars ULONGLONG FatNeeded, ClusterCount; - PrintStatus(0, TRUE, "Formatting (Large FAT32)..."); + // TODO: use another lmsg for Large FAT32 + PrintStatus(0, TRUE, lmprintf(MSG_222, "Large FAT32")); VolumeId = GetVolumeID(); // Open the drive and lock it @@ -552,7 +554,7 @@ static BOOL FormatFAT32(DWORD DriveIndex) if (GetTickCount() > LastRefresh + 25) { LastRefresh = GetTickCount(); format_percent = (100.0f*i)/(1.0f*(SystemAreaSize+BurstSize)); - PrintStatus(0, FALSE, "Formatting: %0.1f%% completed.", format_percent); + PrintStatus(0, FALSE, lmprintf(MSG_217, format_percent)); UpdateProgress(OP_FORMAT, format_percent); } if (IS_ERROR(FormatStatus)) goto out; // For cancellation @@ -577,7 +579,7 @@ static BOOL FormatFAT32(DWORD DriveIndex) } // Must do it here, as have issues when trying to write the PBR after a remount - PrintStatus(0, TRUE, "Writing partition boot record..."); + PrintStatus(0, TRUE, lmprintf(MSG_229)); if (!WritePBR(hLogicalVolume)) { // Non fatal error, but the drive probably won't boot uprintf("Could not write partition boot record - drive may not boot...\n"); @@ -586,7 +588,7 @@ static BOOL FormatFAT32(DWORD DriveIndex) // Set the FAT32 volume label GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel)); ToValidLabel(wLabel, TRUE); - PrintStatus(0, TRUE, "Setting Label (This may take while)..."); + PrintStatus(0, TRUE, lmprintf(MSG_221)); // Handle must be closed for SetVolumeLabel to work safe_closehandle(hLogicalVolume); VolumeName = GetLogicalName(DriveIndex, TRUE, TRUE); @@ -617,17 +619,16 @@ static BOOL FormatDrive(DWORD DriveIndex) { BOOL r = FALSE; PF_DECL(FormatEx); - char FSType[32], format_status[64]; + char FSType[32]; char *locale, *VolumeName = NULL; WCHAR* wVolumeName = NULL; - WCHAR wFSType[32]; + WCHAR wFSType[64]; WCHAR wLabel[64]; ULONG ulClusterSize; size_t i; - GetWindowTextA(hFileSystem, FSType, ARRAYSIZE(FSType)); - safe_sprintf(format_status, ARRAYSIZE(format_status), "Formatting (%s)...", FSType); - PrintStatus(0, TRUE, format_status); + GetWindowTextU(hFileSystem, FSType, ARRAYSIZE(FSType)); + PrintStatus(0, TRUE, lmprintf(MSG_222, FSType)); VolumeName = GetLogicalName(DriveIndex, FALSE, TRUE); wVolumeName = utf8_to_wchar(VolumeName); if (wVolumeName == NULL) { @@ -689,7 +690,7 @@ static BOOL CheckDisk(char DriveLetter) size_t i; wDriveRoot[0] = (WCHAR)DriveLetter; - PrintStatus(0, TRUE, "NTFS Fixup (Checkdisk)..."); + PrintStatus(0, TRUE, lmprintf(MSG_223)); PF_INIT_OR_OUT(Chkdsk, fmifs); @@ -781,7 +782,7 @@ static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSi uint64_t i, last_sector = DiskSize/SectorSize; unsigned char* pBuf = (unsigned char*) calloc(SectorSize, 1); - PrintStatus(0, TRUE, "Clearing MBR/PBR/GPT structures..."); + PrintStatus(0, TRUE, lmprintf(MSG_224)); if (pBuf == NULL) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY; goto out; @@ -1166,9 +1167,8 @@ DWORD WINAPI FormatThread(LPVOID param) HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; HANDLE hLogicalVolume = INVALID_HANDLE_VALUE; SYSTEMTIME lt; - char* guid_volume = NULL; + char *bb_msg, *guid_volume = NULL; char drive_name[] = "?:\\"; - char bb_msg[512]; char logfile[MAX_PATH], *userdir; char wim_image[] = "?:\\sources\\install.wim"; char efi_dst[] = "?:\\efi\\boot\\bootx64.efi"; @@ -1180,7 +1180,7 @@ DWORD WINAPI FormatThread(LPVOID param) bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)); - PrintStatus(0, TRUE, "Requesting disk access...\n"); + PrintStatus(0, TRUE, lmprintf(MSG_225)); hPhysicalDrive = GetPhysicalHandle(DriveIndex, TRUE, TRUE); if (hPhysicalDrive == INVALID_HANDLE_VALUE) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; @@ -1217,7 +1217,7 @@ DWORD WINAPI FormatThread(LPVOID param) } CHECK_FOR_USER_CANCEL; - PrintStatus(0, TRUE, "Analyzing existing boot records...\n"); + PrintStatus(0, TRUE, lmprintf(MSG_226)); AnalyzeMBR(hPhysicalDrive); if ((hLogicalVolume != NULL) && (hLogicalVolume != INVALID_HANDLE_VALUE)) { AnalyzePBR(hLogicalVolume); @@ -1267,19 +1267,15 @@ DWORD WINAPI FormatThread(LPVOID param) report.num_read_errors, report.num_write_errors, report.num_corruption_errors); r = IDOK; if (report.bb_count) { - safe_sprintf(bb_msg, sizeof(bb_msg), "Check completed: %u bad block%s found.\n" - " %d read errors\n %d write errors\n %d corruption errors\n", - report.bb_count, (report.bb_count==1)?"":"s", - report.num_read_errors, report.num_write_errors, + bb_msg = lmprintf(MSG_011, report.num_read_errors, report.num_write_errors, report.num_corruption_errors); - fprintf(log_fd, "%s", bb_msg); + fprintf(log_fd, bb_msg); GetLocalTime(<); fprintf(log_fd, APPLICATION_NAME " bad blocks check ended on: %04d.%02d.%02d %02d:%02d:%02d\n", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); fclose(log_fd); - safe_sprintf(&bb_msg[strlen(bb_msg)], sizeof(bb_msg)-strlen(bb_msg)-1, - "\nA more detailed report can be found in:\n%s\n", logfile); - r = MessageBoxU(hMainDialog, bb_msg, "Bad blocks found", MB_ABORTRETRYIGNORE|MB_ICONWARNING); + r = MessageBoxU(hMainDialog, lmprintf(MSG_012, bb_msg, logfile), + lmprintf(MSG_010), MB_ABORTRETRYIGNORE|MB_ICONWARNING); } else { // We didn't get any errors => delete the log file fclose(log_fd); @@ -1293,7 +1289,7 @@ DWORD WINAPI FormatThread(LPVOID param) } // Close the (unmounted) volume before formatting if ((hLogicalVolume != NULL) && (hLogicalVolume != INVALID_HANDLE_VALUE)) { - PrintStatus(0, TRUE, "Closing existing volume...\n"); + PrintStatus(0, TRUE, lmprintf(MSG_227)); if (!CloseHandle(hLogicalVolume)) { uprintf("Could not close volume: %s\n", WindowsErrorString()); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED; @@ -1339,7 +1335,7 @@ DWORD WINAPI FormatThread(LPVOID param) // Thanks to Microsoft, we must fix the MBR AFTER the drive has been formatted if (pt == PARTITION_STYLE_MBR) { - PrintStatus(0, TRUE, "Writing master boot record..."); + PrintStatus(0, TRUE, lmprintf(MSG_228)); if (!WriteMBR(hPhysicalDrive)) { if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; @@ -1386,7 +1382,7 @@ DWORD WINAPI FormatThread(LPVOID param) } // NB: if you unmount the logical volume here, XP will report error: // [0x00000456] The media in the drive may have changed - PrintStatus(0, TRUE, "Writing partition boot record..."); + PrintStatus(0, TRUE, lmprintf(MSG_229)); if (!WritePBR(hLogicalVolume)) { if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; @@ -1415,7 +1411,7 @@ DWORD WINAPI FormatThread(LPVOID param) if (IsChecked(IDC_BOOT)) { if ((dt == DT_WINME) || (dt == DT_FREEDOS)) { UpdateProgress(OP_DOS, -1.0f); - PrintStatus(0, TRUE, "Copying DOS files..."); + PrintStatus(0, TRUE, lmprintf(MSG_230)); if (!ExtractDOS(drive_name)) { if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; @@ -1424,7 +1420,7 @@ DWORD WINAPI FormatThread(LPVOID param) } else if (dt == DT_ISO) { if (iso_path != NULL) { UpdateProgress(OP_DOS, 0.0f); - PrintStatus(0, TRUE, "Copying ISO files..."); + PrintStatus(0, TRUE, lmprintf(MSG_231)); drive_name[2] = 0; if (!ExtractISO(iso_path, drive_name, FALSE)) { if (!IS_ERROR(FormatStatus)) @@ -1433,7 +1429,7 @@ DWORD WINAPI FormatThread(LPVOID param) } if ((bt == BT_UEFI) && (!iso_report.has_efi) && (iso_report.has_win7_efi)) { // TODO: (v1.4.0) check ISO with EFI only - PrintStatus(0, TRUE, "Win7 EFI boot setup (this may take a while)..."); + PrintStatus(0, TRUE, lmprintf(MSG_232)); wim_image[0] = drive_name[0]; efi_dst[0] = drive_name[0]; efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = 0; @@ -1456,7 +1452,7 @@ DWORD WINAPI FormatThread(LPVOID param) } } UpdateProgress(OP_FINALIZE, -1.0f); - PrintStatus(0, TRUE, "Finalizing, please wait..."); + PrintStatus(0, TRUE, lmprintf(MSG_233)); if (IsChecked(IDC_SET_ICON)) SetAutorun(drive_name); // Issue another complete remount before we exit, to ensure we're clean diff --git a/src/iso.c b/src/iso.c index ada677f3..33364e11 100644 --- a/src/iso.c +++ b/src/iso.c @@ -41,6 +41,7 @@ #include "rufus.h" #include "msapi_utf8.h" #include "resource.h" +#include "localization.h" // How often should we update the progress bar (in 2K blocks) as updating // the progress bar for every block will bring extraction to a crawl @@ -77,16 +78,15 @@ static __inline char* size_to_hr(int64_t size) { int suffix = 0; static char str_size[24]; - const char* sizes[] = { "", "KB", "MB", "GB", "TB" }; double hr_size = (double)size; - while ((suffix < ARRAYSIZE(sizes)) && (hr_size >= 1024.0)) { + while ((suffix < MAX_SIZE_SUFFIXES) && (hr_size >= 1024.0)) { hr_size /= 1024.0; suffix++; } if (suffix == 0) { - safe_sprintf(str_size, sizeof(str_size), " (%d bytes)", (int)hr_size); + safe_sprintf(str_size, sizeof(str_size), " (%d %s)", (int)hr_size, lmprintf(MSG_020)); } else { - safe_sprintf(str_size, sizeof(str_size), " (%0.1f %s)", hr_size, sizes[suffix]); + safe_sprintf(str_size, sizeof(str_size), " (%0.1f %s)", hr_size, lmprintf(MSG_020+suffix)); } return str_size; } @@ -419,7 +419,6 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan) LONG progress_style; char* tmp; char path[64]; - const char* scan_text = "Scanning ISO image..."; const char* basedir[] = { "i386", "minint" }; const char* tmp_sif = ".\\txtsetup.sif~"; iso_extension_mask_t iso_extension_mask = ISO_EXTENSION_ALL; @@ -437,14 +436,14 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan) // String array of all isolinux/syslinux locations StrArrayCreate(&config_path, 8); // Change the Window title and static text - SetWindowTextU(hISOProgressDlg, scan_text); - SetWindowTextU(hISOFileName, scan_text); + SetWindowTextU(hISOProgressDlg, lmprintf(MSG_202)); + SetWindowTextU(hISOFileName, lmprintf(MSG_202)); // Change progress style to marquee for scanning SetWindowLong(hISOProgressBar, GWL_STYLE, progress_style | PBS_MARQUEE); SendMessage(hISOProgressBar, PBM_SETMARQUEE, TRUE, 0); } else { uprintf("Extracting files...\n"); - SetWindowTextU(hISOProgressDlg, "Copying ISO files..."); + SetWindowTextU(hISOProgressDlg, lmprintf(MSG_231)); if (total_blocks == 0) { uprintf("Error: ISO has not been properly scanned.\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_SCAN); @@ -506,7 +505,7 @@ out: iso_blocking_status = -1; if (scan_only) { // Remove trailing spaces from the label - for (j=(int)safe_strlen(iso_report.label)-1; ((j>=0)&&(isspace(iso_report.label[j]))); j--) + for (j=(int)safe_strlen(iso_report.label)-1; ((j>=0)&&(isspaceU(iso_report.label[j]))); j--) iso_report.label[j] = 0; // We use the fact that UDF_BLOCKSIZE and ISO_BLOCKSIZE are the same here iso_report.projected_size = total_blocks * ISO_BLOCKSIZE; diff --git a/src/license.h b/src/license.h index a9331698..ce3b475c 100644 --- a/src/license.h +++ b/src/license.h @@ -19,16 +19,17 @@ const char* about_blurb_format = "{\\rtf1\\ansi\n" -"{\\b\\fs20Rufus - The Reliable USB Formatting Utility}\\line\n" -"\\fs18Version %d.%d.%d (Build %d)\\line\n" +"{\\b\\fs20%s}\\line\n" +"\\fs18%s\\line\n" "\\line\n" "Copyright © 2011-2013 Pete Batard / Akeo\\line\n" RUFUS_URL "\\line\n" +"%s\\line\n" "\\line\n" -"Report bugs or request enhancements at:\\line\n" +"%s\\line\n" "https://github.com/pbatard/rufus/issues\\line\n" "\\line\n" -"{\\b\\fs18Additional Copyrights:}}"; +"{\\b\\fs18 %s}}"; const char* additional_copyrights = "{\\rtf1\\ansi\n" @@ -90,17 +91,15 @@ const char* additional_copyrights = const char* update_policy = "{\\rtf1\\ansi{\\fonttbl{\\f0\\fnil\\fcharset0 Microsoft Sans Serif;}{\\f1\\fnil\\fcharset2 Symbol;}}\n" -"\\fs16\\b Update Policy:\\b0\\line\n" -"If you choose to allow this program to check for application updates, you agree that the following information may be collected on our server(s):\\par\n" -"\\pard{\\pntext\\f1\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\fi-150\\li220 Your operating system's architecture and version\\par\n" -"{\\pntext\\f1\\'B7\\tab}The version of the application you use\\par\n" -"{\\pntext\\f1\\'B7\\tab}Your IP address\\line\\pard\n" +"\\fs16\\b %s\\b0\\line\n" +"%s:\\par\n" +"\\pard{\\pntext\\f1\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf2\\pnindent0{\\pntxtb\\'B7}}\\fi-150\\li220 %s\\par\n" +"{\\pntext\\f1\\'B7\\tab}%s\\par\n" +"{\\pntext\\f1\\'B7\\tab}%s\\line\\pard\n" "\\line\n" -"For the purpose of generating private usage statistics, we may keep the information collected, \n" -"\\b for at most a year\\b0 . However, we will not willingly disclose any of this individual data to third parties.\\line\n\\line\n" -"\\b Update Process:\\b0\\line\n" -APPLICATION_NAME " does not install or run background services, therefore update checks are performed only when the main application is running.\\line\n" -"Internet access is of course required when checking for updates.\\line\n" +"%s\\line\n\\line\n" +"\\b %s\\b0\\line\n" +"%s\\line\n" "}"; const char* gplv3 = diff --git a/src/localization.c b/src/localization.c new file mode 100644 index 00000000..d4aa9ea6 --- /dev/null +++ b/src/localization.c @@ -0,0 +1,368 @@ +/* + * Rufus: The Reliable USB Formatting Utility + * Localization functions, a.k.a. "Everybody is doing it wrong but me!" + * Copyright © 2013 Pete Batard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "rufus.h" +#include "resource.h" +#include "msapi_utf8.h" +#include "localization.h" +#include "localization_data.h" + +/* + * List of supported locale commands, with their parameter syntax: + * c control ID (no space, no quotes) + * s: quoted string + * i: 32 bit signed integer + * u: 32 bit unsigned CSV list + * Remember to update the size of the array in localization.h when adding/removing elements + */ +const loc_parse parse_cmd[9] = { + // Translation name and Windows LCIDs it should apply to + { 'l', LC_LOCALE, "ssu" }, // l "en_US" "English (US)" 0x0009,0x1009 + // Base translation to add on top of (eg. "English (UK)" can be used to build on top of "English (US)" + { 'b', LC_BASE, "s" }, // b "en_US" + // Version to use for the localization commandset and API + { 'v', LC_VERSION, "ii" }, // v 1.0 // TODO: NOT IMPLEMENTED YET + // Translate the text control associated with an ID + { 't', LC_TEXT, "cs" }, // t IDC_CONTROL "Translation" + // Set the section/dialog to which the next commands should apply + { 'g', LC_GROUP, "c" }, // g IDD_DIALOG + // Resize a dialog (dx dy pixel increment) + { 's', LC_SIZE, "cii" }, // s IDC_CONTROL +10 +10 + // Move a dialog (dx dy pixed displacement) + { 'm', LC_MOVE, "cii" }, // m IDC_CONTROL -5 0 + // Set the font to use for the text controls that follow + // Use f "Default" 0 to reset the font + { 'f', LC_FONT, "si" }, // f "MS Dialog" 10 + // Set the direction to use for the text controls that follow + // 0 = Left to right, 1 = Right to left + { 'd', LC_DIRECTION, "i" }, // d 1 // TODO: NOT IMPLEMENTED YET +}; + +/* Globals */ +int loc_line_nr; +struct list_head locale_list = {NULL, NULL}; +char *loc_filename = NULL, *embedded_loc_filename = "[embedded] rufus.loc"; + +/* + * Add a localization command to a dialog/section + */ +void add_dialog_command(int index, loc_cmd* lcmd) +{ + if ((lcmd == NULL) || (index < 0) || (index >= ARRAYSIZE(loc_dlg))) { + uprintf("add_dialog_command: invalid parameter\n"); + return; + } + list_add(&lcmd->list, &loc_dlg[index].list); +} + +void free_loc_cmd(loc_cmd* lcmd) +{ + if (lcmd == NULL) + return; + safe_free(lcmd->txt[0]); + safe_free(lcmd->txt[1]); + safe_free(lcmd->unum); + free(lcmd); +} + +void free_dialog_list(void) +{ + size_t i = 0; + loc_cmd *lcmd, *next; + + for (i=0; ilist); + free_loc_cmd(lcmd); + } + } +} + +void free_locale_list(void) +{ + loc_cmd *lcmd, *next; + + list_for_each_entry_safe(lcmd, next, &locale_list, loc_cmd, list) { + list_del(&lcmd->list); + free_loc_cmd(lcmd); + } +} + +/* + * Init/destroy our various localization lists + */ +void init_localization(void) { + size_t i; + for (i=0; icommand <= LC_TEXT) { + // Any command up to LC_TEXT takes a control ID in text[0] + for (i=0; itxt[0], control_id[i].name) == 0) { + lcmd->ctrl_id = control_id[i].id; + break; + } + } + if (lcmd->ctrl_id < 0) { + luprintf("unknown control '%s'\n", lcmd->txt[0]); + goto err; + } + } + + switch(lcmd->command) { + // NB: For commands that take an ID, ctrl_id is always a valid index at this stage + case LC_TEXT: + case LC_MOVE: + case LC_SIZE: + add_dialog_command(dlg_index, lcmd); + break; + case LC_GROUP: + if ((lcmd->ctrl_id-IDD_DIALOG) > ARRAYSIZE(loc_dlg)) { + luprintf("'%s' is not a group ID\n", lcmd->txt[0]); + goto err; + } + dlg_index = lcmd->ctrl_id - IDD_DIALOG; + free_loc_cmd(lcmd); + break; + case LC_VERSION: + luprintf("GOT VERSION: %d.%d\n", lcmd->num[0], lcmd->num[1]); + free_loc_cmd(lcmd); + break; + case LC_BASE: + base_locale = get_locale_from_name(lcmd->txt[0]); + if (base_locale != NULL) { + uprintf("localization: using locale base '%s'", lcmd->txt[0]); + get_loc_data_file(NULL, (long)base_locale->num[0], (long)base_locale->num[1], base_locale->line_nr); + } else { + uprintf("localization: locale base '%s' not found", lcmd->txt[0]); + } + free_loc_cmd(lcmd); + break; + default: + free_loc_cmd(lcmd); + break; + } + return TRUE; + +err: + free_loc_cmd(lcmd); + return FALSE; +} + +/* + * Apply stored localization commands to a specific dialog + * If hDlg is NULL, apply the commands against an active Window + * TODO: if dlg_id is <0, apply all + */ +void apply_localization(int dlg_id, HWND hDlg) +{ + loc_cmd* lcmd; + HWND hCtrl = NULL; + int id_start = IDD_DIALOG, id_end = IDD_DIALOG + ARRAYSIZE(loc_dlg); + LONG_PTR style; + BOOL left_to_right = FALSE; + + if ((dlg_id >= id_start) && (dlg_id < id_end)) { + // If we have a valid dialog_id, just process that one dialog + id_start = dlg_id; + id_end = dlg_id + 1; + if (hDlg != NULL) { + loc_dlg[dlg_id-IDD_DIALOG].hDlg = hDlg; + } + } + + for (dlg_id = id_start; dlg_id < id_end; dlg_id++) { + hDlg = loc_dlg[dlg_id-IDD_DIALOG].hDlg; + if ((!IsWindow(hDlg)) || (list_empty(&loc_dlg[dlg_id-IDD_DIALOG].list))) + continue; + + // TODO: storing the messages in an array indexed on the message ID - 3000 would be faster + list_for_each_entry(lcmd, &loc_dlg[dlg_id-IDD_DIALOG].list, loc_cmd, list) { + if (lcmd->command <= LC_TEXT) { // TODO: should always be the case + if (lcmd->ctrl_id == dlg_id) { + if ((dlg_id == IDD_DIALOG) && (lcmd->txt[1] != NULL) && (lcmd->txt[1][0] != 0)) { + loc_line_nr = lcmd->line_nr; + luprint("operation forbidden (main dialog title cannot be changed)"); + continue; + } + hCtrl = hDlg; + } else { + hCtrl = GetDlgItem(hDlg, lcmd->ctrl_id); + } + if (hCtrl == NULL) { + loc_line_nr = lcmd->line_nr; + luprintf("control '%s' is not part of dialog '%s'\n", + lcmd->txt[0], control_id[dlg_id-IDD_DIALOG].name); + } + } + + switch(lcmd->command) { + // NB: For commands that take an ID, ctrl_id is always a valid index at this stage + case LC_TEXT: + if (hCtrl != NULL) { + if ((lcmd->txt[1] != NULL) && (lcmd->txt[1][0] != 0)) + SetWindowTextU(hCtrl, lcmd->txt[1]); + if (left_to_right) { + style = GetWindowLongPtr(hCtrl, GWL_EXSTYLE); + style |= WS_EX_LAYOUTRTL; // WS_EX_RIGHT | WS_EX_RTLREADING + SetWindowLongPtr(hCtrl, GWL_EXSTYLE, style); + InvalidateRect(hCtrl, NULL, TRUE); + } + } + break; + case LC_MOVE: + if (hCtrl != NULL) { + ResizeMoveCtrl(hDlg, hCtrl, lcmd->num[0], lcmd->num[1], 0, 0); + } + break; + case LC_SIZE: + if (hCtrl != NULL) { + ResizeMoveCtrl(hDlg, hCtrl, 0, 0, lcmd->num[0], lcmd->num[1]); + } + break; + } + } + } +} + +/* + * This function should be called when a localized dialog is destroyed + * NB: we can't use isWindow() against our existing HWND to avoid this call + * as handles are recycled. + */ +void reset_localization(int dlg_id) +{ + loc_dlg[dlg_id-IDD_DIALOG].hDlg = NULL; +} + +/* + * Produce a formatted localized message. + * Like printf, this call takes a variable number of argument, and uses + * the message ID to identify the formatted message to use. + * Uses a rolling list of buffers to allow concurrency + * TODO: use dynamic realloc'd buffer in case LOC_MESSAGE_SIZE is not enough + */ +char* lmprintf(int msg_id, ...) +{ + static int buf_id = 0; + static char buf[LOC_MESSAGE_NB][LOC_MESSAGE_SIZE]; + char *format = NULL; + va_list args; + loc_cmd* lcmd; + buf_id %= LOC_MESSAGE_NB; + buf[buf_id][0] = 0; + list_for_each_entry(lcmd, &loc_dlg[IDD_MESSAGES-IDD_DIALOG].list, loc_cmd, list) { + if ((lcmd->command == LC_TEXT) && (lcmd->ctrl_id == msg_id) && (lcmd->txt[1] != NULL)) { + format = lcmd->txt[1]; + } + } + + if (format == NULL) { + safe_sprintf(buf[buf_id], LOC_MESSAGE_SIZE-1, "MSG_%03d UNTRANSLATED", msg_id - MSG_000); + } else { + va_start(args, msg_id); + safe_vsnprintf(buf[buf_id], LOC_MESSAGE_SIZE-1, format, args); + va_end(args); + buf[buf_id][LOC_MESSAGE_SIZE-1] = '\0'; + } + return buf[buf_id++]; +} + +/* + * These 2 functions are used to set the current locale + */ +loc_cmd* get_locale_from_lcid(int lcid) +{ + loc_cmd* lcmd = NULL; + int i; + + if (list_empty(&locale_list)) { + uprintf("localization: the locale list is empty!\n"); + return NULL; + } + + list_for_each_entry(lcmd, &locale_list, loc_cmd, list) { + for (i=0; iunum_size; i++) { + if (lcmd->unum[i] == lcid) { + return lcmd; + } + } + } + + lcmd = list_entry(locale_list.next, loc_cmd, list); + // If we couldn't find a supported locale, just pick the first one (usually English) + uprintf("localization: could not find locale for LCID: 0x%04X. Will default to '%s'\n", lcid, lcmd->txt[0]); + return lcmd; +} + +loc_cmd* get_locale_from_name(char* locale_name) +{ + loc_cmd* lcmd = NULL; + + if (list_empty(&locale_list)) { + uprintf("localization: the locale list is empty!\n"); + return NULL; + } + + list_for_each_entry(lcmd, &locale_list, loc_cmd, list) { + if (safe_strcmp(lcmd->txt[0], locale_name) == 0) + return lcmd; + } + + lcmd = list_entry(locale_list.next, loc_cmd, list); + uprintf("localization: could not find locale for name '%s'. Will default to '%s'\n", locale_name, lcmd->txt[0]); + return lcmd; +} diff --git a/src/localization.h b/src/localization.h new file mode 100644 index 00000000..23d6919b --- /dev/null +++ b/src/localization.h @@ -0,0 +1,158 @@ +/* + * Rufus: The Reliable USB Formatting Utility + * Localization functions, a.k.a. "Everybody is doing it wrong but me!" + * Copyright © 2013 Pete Batard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#pragma once + +// Number of concurrent localization messages. Must be a power of 2. +#define LOC_MESSAGE_NB 8 +#define LOC_MESSAGE_SIZE 2048 + +#define luprint(msg) uprintf("%s(%d): " msg "\n", loc_filename, loc_line_nr) +#define luprintf(msg, ...) uprintf("%s(%d): " msg "\n", loc_filename, loc_line_nr, __VA_ARGS__) + +/* + * List handling functions (stolen from libusb) + * NB: offsetof() requires '#include ' + */ +struct list_head { + struct list_head *prev, *next; +}; + +/* Get an entry from the list + * ptr - the address of this list_head element in "type" + * type - the data type that contains "member" + * member - the list_head element in "type" + */ +#define list_entry(ptr, type, member) \ + ((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member))) + +/* Get each entry from a list + * pos - A structure pointer has a "member" element + * head - list head + * member - the list_head element in "pos" + * type - the type of the first parameter + */ +#define list_for_each_entry(pos, head, type, member) \ + for (pos = list_entry((head)->next, type, member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) + + +#define list_for_each_entry_safe(pos, n, head, type, member) \ + for (pos = list_entry((head)->next, type, member), \ + n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, type, member)) + +#define list_empty(entry) ((entry)->next == (entry)) + +static __inline void list_init(struct list_head *entry) +{ + entry->prev = entry->next = entry; +} + +static __inline void list_add(struct list_head *entry, struct list_head *head) +{ + entry->next = head->next; + entry->prev = head; + + head->next->prev = entry; + head->next = entry; +} + +static __inline void list_add_tail(struct list_head *entry, + struct list_head *head) +{ + entry->next = head; + entry->prev = head->prev; + + head->prev->next = entry; + head->prev = entry; +} + +static __inline void list_del(struct list_head *entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + entry->next = entry->prev = NULL; +} + +// Commands that take a control ID *MUST* be at the top +// The last command with a control ID *MUST* be LC_TEXT +enum loc_command_type { + LC_GROUP, + LC_MOVE, + LC_SIZE, + LC_TEXT, // Delimits commands that take a Control ID and commands that don't + LC_VERSION, + LC_LOCALE, + LC_BASE, + LC_FONT, + LC_DIRECTION, +}; + +typedef struct loc_cmd_struct { + uint8_t command; + uint8_t unum_size; + uint16_t line_nr; + int ctrl_id; + int32_t num[2]; + uint32_t* unum; + char* txt[2]; + struct list_head list; +} loc_cmd; + +typedef struct loc_parse_struct { + char c; + enum loc_command_type cmd; + char* arg_type; +} loc_parse; + +typedef struct loc_control_id_struct { + const char* name; + const int id; +} loc_control_id; + +typedef struct loc_dlg_list_struct { + const int dlg_id; + HWND hDlg; + struct list_head list; +} loc_dlg_list; + +extern const loc_parse parse_cmd[9]; +extern struct list_head locale_list; +int loc_line_nr; +char *loc_filename, *embedded_loc_filename; + +void free_loc_cmd(loc_cmd* lcmd); +BOOL dispatch_loc_cmd(loc_cmd* lcmd); +void init_localization(void); +void exit_localization(void); +void apply_localization(int dlg_id, HWND hDlg); +void reset_localization(int dlg_id); +void free_dialog_list(void); +char* lmprintf(int msg_id, ...); +BOOL get_supported_locales(const char* filename); +char* get_loc_data_file(const char* filename, long offset, long end_offset, int start_line); +void free_locale_list(void); +loc_cmd* get_locale_from_lcid(int lcid); +loc_cmd* get_locale_from_name(char* locale_name); diff --git a/src/localization_data.h b/src/localization_data.h new file mode 100644 index 00000000..d449886c --- /dev/null +++ b/src/localization_data.h @@ -0,0 +1,382 @@ +/* + * Rufus: The Reliable USB Formatting Utility + * Localization tables - autogenerated from resource.h + * Copyright © 2013 Pete Batard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "resource.h" +#include "localization.h" + +#define LOC_CTRL(x) { #x, x } +#define LOC_DLG(x) { x, NULL, {NULL, NULL} } + +// Control IDs +const loc_control_id control_id[] = { + // The dialog IDs must come first + LOC_CTRL(IDD_DIALOG), + LOC_CTRL(IDD_ABOUTBOX), + LOC_CTRL(IDD_NOTIFICATION), + LOC_CTRL(IDD_LICENSE), + LOC_CTRL(IDD_ISO_EXTRACT), + LOC_CTRL(IDD_LOG), + LOC_CTRL(IDD_UPDATE_POLICY), + LOC_CTRL(IDD_NEW_VERSION), + LOC_CTRL(IDD_MESSAGES), + LOC_CTRL(IDC_DEVICE), + LOC_CTRL(IDC_FILESYSTEM), + LOC_CTRL(IDC_START), + LOC_CTRL(IDC_PARTITION_TYPE), + LOC_CTRL(IDC_CLUSTERSIZE), + LOC_CTRL(IDC_STATUS), + LOC_CTRL(IDC_ABOUT), + LOC_CTRL(IDC_LABEL), + LOC_CTRL(IDC_QUICKFORMAT), + LOC_CTRL(IDC_BOOT), + LOC_CTRL(IDC_BADBLOCKS), + LOC_CTRL(IDC_PROGRESS), + LOC_CTRL(IDC_BOOTTYPE), + LOC_CTRL(IDC_NBPASSES), + LOC_CTRL(IDC_TEST), + LOC_CTRL(IDC_SELECT_ISO), + LOC_CTRL(IDC_SET_ICON), + LOC_CTRL(IDC_RUFUS_MBR), + LOC_CTRL(IDC_ISO_FILENAME), + LOC_CTRL(IDC_ISO_ABORT), + LOC_CTRL(IDC_DISK_ID), + LOC_CTRL(IDC_EXTRA_PARTITION), + LOC_CTRL(IDC_ENABLE_FIXED_DISKS), + LOC_CTRL(IDC_ABOUT_LICENSE), + LOC_CTRL(IDC_ABOUT_ICON), + LOC_CTRL(IDC_ABOUT_UPDATES), + LOC_CTRL(IDC_ABOUT_COPYRIGHTS), + LOC_CTRL(IDC_ABOUT_BLURB), + LOC_CTRL(IDC_LICENSE_TEXT), + LOC_CTRL(IDC_NOTIFICATION_ICON), + LOC_CTRL(IDC_NOTIFICATION_TEXT), + LOC_CTRL(IDC_NOTIFICATION_LINE), + LOC_CTRL(IDC_ADVANCED), + LOC_CTRL(IDS_ADVANCED_OPTIONS_GRP), + LOC_CTRL(IDC_LOG), + LOC_CTRL(IDC_LOG_EDIT), + LOC_CTRL(IDC_LOG_SAVE), + LOC_CTRL(IDC_LOG_CLEAR), + LOC_CTRL(IDC_MORE_INFO), + LOC_CTRL(IDC_POLICY), + LOC_CTRL(IDC_UPDATE_FREQUENCY), + LOC_CTRL(IDC_INCLUDE_BETAS), + LOC_CTRL(IDC_RELEASE_NOTES), + LOC_CTRL(IDC_DOWNLOAD), + LOC_CTRL(IDC_CHECK_NOW), + LOC_CTRL(IDC_WEBSITE), + LOC_CTRL(IDC_YOUR_VERSION), + LOC_CTRL(IDC_LATEST_VERSION), + LOC_CTRL(IDC_DOWNLOAD_URL), + LOC_CTRL(IDS_DEVICE_TXT), + LOC_CTRL(IDS_PARTITION_TYPE_TXT), + LOC_CTRL(IDS_FILESYSTEM_TXT), + LOC_CTRL(IDS_CLUSTERSIZE_TXT), + LOC_CTRL(IDS_LABEL_TXT), + LOC_CTRL(IDS_FORMAT_OPTIONS_GRP), + LOC_CTRL(IDS_UPDATE_SETTINGS_GRP), + LOC_CTRL(IDS_UPDATE_FREQUENCY_TXT), + LOC_CTRL(IDS_INCLUDE_BETAS_TXT), + LOC_CTRL(IDS_NEW_VERSION_AVAIL_TXT), + LOC_CTRL(IDS_NEW_VERSION_DOWNLOAD_GRP), + LOC_CTRL(IDS_NEW_VERSION_NOTES_GRP), + LOC_CTRL(IDS_CHECK_NOW_GRP), + LOC_CTRL(MSG_000), + LOC_CTRL(MSG_001), + LOC_CTRL(MSG_002), + LOC_CTRL(MSG_003), + LOC_CTRL(MSG_004), + LOC_CTRL(MSG_005), + LOC_CTRL(MSG_006), + LOC_CTRL(MSG_007), + LOC_CTRL(MSG_008), + LOC_CTRL(MSG_009), + LOC_CTRL(MSG_010), + LOC_CTRL(MSG_011), + LOC_CTRL(MSG_012), + LOC_CTRL(MSG_013), + LOC_CTRL(MSG_014), + LOC_CTRL(MSG_015), + LOC_CTRL(MSG_016), + LOC_CTRL(MSG_017), + LOC_CTRL(MSG_018), + LOC_CTRL(MSG_019), + LOC_CTRL(MSG_020), + LOC_CTRL(MSG_021), + LOC_CTRL(MSG_022), + LOC_CTRL(MSG_023), + LOC_CTRL(MSG_024), + LOC_CTRL(MSG_025), + LOC_CTRL(MSG_026), + LOC_CTRL(MSG_027), + LOC_CTRL(MSG_028), + LOC_CTRL(MSG_029), + LOC_CTRL(MSG_030), + LOC_CTRL(MSG_031), + LOC_CTRL(MSG_032), + LOC_CTRL(MSG_033), + LOC_CTRL(MSG_034), + LOC_CTRL(MSG_035), + LOC_CTRL(MSG_036), + LOC_CTRL(MSG_037), + LOC_CTRL(MSG_038), + LOC_CTRL(MSG_039), + LOC_CTRL(MSG_040), + LOC_CTRL(MSG_041), + LOC_CTRL(MSG_042), + LOC_CTRL(MSG_043), + LOC_CTRL(MSG_044), + LOC_CTRL(MSG_045), + LOC_CTRL(MSG_046), + LOC_CTRL(MSG_047), + LOC_CTRL(MSG_048), + LOC_CTRL(MSG_049), + LOC_CTRL(MSG_050), + LOC_CTRL(MSG_051), + LOC_CTRL(MSG_052), + LOC_CTRL(MSG_053), + LOC_CTRL(MSG_054), + LOC_CTRL(MSG_055), + LOC_CTRL(MSG_056), + LOC_CTRL(MSG_057), + LOC_CTRL(MSG_058), + LOC_CTRL(MSG_059), + LOC_CTRL(MSG_060), + LOC_CTRL(MSG_061), + LOC_CTRL(MSG_062), + LOC_CTRL(MSG_063), + LOC_CTRL(MSG_064), + LOC_CTRL(MSG_065), + LOC_CTRL(MSG_066), + LOC_CTRL(MSG_067), + LOC_CTRL(MSG_068), + LOC_CTRL(MSG_069), + LOC_CTRL(MSG_070), + LOC_CTRL(MSG_071), + LOC_CTRL(MSG_072), + LOC_CTRL(MSG_073), + LOC_CTRL(MSG_074), + LOC_CTRL(MSG_075), + LOC_CTRL(MSG_076), + LOC_CTRL(MSG_077), + LOC_CTRL(MSG_078), + LOC_CTRL(MSG_079), + LOC_CTRL(MSG_080), + LOC_CTRL(MSG_081), + LOC_CTRL(MSG_082), + LOC_CTRL(MSG_083), + LOC_CTRL(MSG_084), + LOC_CTRL(MSG_085), + LOC_CTRL(MSG_086), + LOC_CTRL(MSG_087), + LOC_CTRL(MSG_088), + LOC_CTRL(MSG_089), + LOC_CTRL(MSG_090), + LOC_CTRL(MSG_091), + LOC_CTRL(MSG_092), + LOC_CTRL(MSG_093), + LOC_CTRL(MSG_094), + LOC_CTRL(MSG_095), + LOC_CTRL(MSG_096), + LOC_CTRL(MSG_097), + LOC_CTRL(MSG_098), + LOC_CTRL(MSG_099), + LOC_CTRL(MSG_100), + LOC_CTRL(MSG_101), + LOC_CTRL(MSG_102), + LOC_CTRL(MSG_103), + LOC_CTRL(MSG_104), + LOC_CTRL(MSG_105), + LOC_CTRL(MSG_106), + LOC_CTRL(MSG_107), + LOC_CTRL(MSG_108), + LOC_CTRL(MSG_109), + LOC_CTRL(MSG_110), + LOC_CTRL(MSG_111), + LOC_CTRL(MSG_112), + LOC_CTRL(MSG_113), + LOC_CTRL(MSG_114), + LOC_CTRL(MSG_115), + LOC_CTRL(MSG_116), + LOC_CTRL(MSG_117), + LOC_CTRL(MSG_118), + LOC_CTRL(MSG_119), + LOC_CTRL(MSG_120), + LOC_CTRL(MSG_121), + LOC_CTRL(MSG_122), + LOC_CTRL(MSG_123), + LOC_CTRL(MSG_124), + LOC_CTRL(MSG_125), + LOC_CTRL(MSG_126), + LOC_CTRL(MSG_127), + LOC_CTRL(MSG_128), + LOC_CTRL(MSG_129), + LOC_CTRL(MSG_130), + LOC_CTRL(MSG_131), + LOC_CTRL(MSG_132), + LOC_CTRL(MSG_133), + LOC_CTRL(MSG_134), + LOC_CTRL(MSG_135), + LOC_CTRL(MSG_136), + LOC_CTRL(MSG_137), + LOC_CTRL(MSG_138), + LOC_CTRL(MSG_139), + LOC_CTRL(MSG_140), + LOC_CTRL(MSG_141), + LOC_CTRL(MSG_142), + LOC_CTRL(MSG_143), + LOC_CTRL(MSG_144), + LOC_CTRL(MSG_145), + LOC_CTRL(MSG_146), + LOC_CTRL(MSG_147), + LOC_CTRL(MSG_148), + LOC_CTRL(MSG_149), + LOC_CTRL(MSG_150), + LOC_CTRL(MSG_151), + LOC_CTRL(MSG_152), + LOC_CTRL(MSG_153), + LOC_CTRL(MSG_154), + LOC_CTRL(MSG_155), + LOC_CTRL(MSG_156), + LOC_CTRL(MSG_157), + LOC_CTRL(MSG_158), + LOC_CTRL(MSG_159), + LOC_CTRL(MSG_160), + LOC_CTRL(MSG_161), + LOC_CTRL(MSG_162), + LOC_CTRL(MSG_163), + LOC_CTRL(MSG_164), + LOC_CTRL(MSG_165), + LOC_CTRL(MSG_166), + LOC_CTRL(MSG_167), + LOC_CTRL(MSG_168), + LOC_CTRL(MSG_169), + LOC_CTRL(MSG_170), + LOC_CTRL(MSG_171), + LOC_CTRL(MSG_172), + LOC_CTRL(MSG_173), + LOC_CTRL(MSG_174), + LOC_CTRL(MSG_175), + LOC_CTRL(MSG_176), + LOC_CTRL(MSG_177), + LOC_CTRL(MSG_178), + LOC_CTRL(MSG_179), + LOC_CTRL(MSG_180), + LOC_CTRL(MSG_181), + LOC_CTRL(MSG_182), + LOC_CTRL(MSG_183), + LOC_CTRL(MSG_184), + LOC_CTRL(MSG_185), + LOC_CTRL(MSG_186), + LOC_CTRL(MSG_187), + LOC_CTRL(MSG_188), + LOC_CTRL(MSG_189), + LOC_CTRL(MSG_190), + LOC_CTRL(MSG_191), + LOC_CTRL(MSG_192), + LOC_CTRL(MSG_193), + LOC_CTRL(MSG_194), + LOC_CTRL(MSG_195), + LOC_CTRL(MSG_196), + LOC_CTRL(MSG_197), + LOC_CTRL(MSG_198), + LOC_CTRL(MSG_199), + LOC_CTRL(MSG_200), + LOC_CTRL(MSG_201), + LOC_CTRL(MSG_202), + LOC_CTRL(MSG_203), + LOC_CTRL(MSG_204), + LOC_CTRL(MSG_205), + LOC_CTRL(MSG_206), + LOC_CTRL(MSG_207), + LOC_CTRL(MSG_208), + LOC_CTRL(MSG_209), + LOC_CTRL(MSG_210), + LOC_CTRL(MSG_211), + LOC_CTRL(MSG_212), + LOC_CTRL(MSG_213), + LOC_CTRL(MSG_214), + LOC_CTRL(MSG_215), + LOC_CTRL(MSG_216), + LOC_CTRL(MSG_217), + LOC_CTRL(MSG_218), + LOC_CTRL(MSG_219), + LOC_CTRL(MSG_220), + LOC_CTRL(MSG_221), + LOC_CTRL(MSG_222), + LOC_CTRL(MSG_223), + LOC_CTRL(MSG_224), + LOC_CTRL(MSG_225), + LOC_CTRL(MSG_226), + LOC_CTRL(MSG_227), + LOC_CTRL(MSG_228), + LOC_CTRL(MSG_229), + LOC_CTRL(MSG_230), + LOC_CTRL(MSG_231), + LOC_CTRL(MSG_232), + LOC_CTRL(MSG_233), + LOC_CTRL(MSG_234), + LOC_CTRL(MSG_235), + LOC_CTRL(MSG_236), + LOC_CTRL(MSG_237), + LOC_CTRL(MSG_238), + LOC_CTRL(MSG_239), + LOC_CTRL(MSG_240), + LOC_CTRL(MSG_241), + LOC_CTRL(MSG_242), + LOC_CTRL(MSG_243), + LOC_CTRL(MSG_244), + LOC_CTRL(MSG_245), + LOC_CTRL(MSG_246), + LOC_CTRL(MSG_247), + LOC_CTRL(MSG_248), + LOC_CTRL(MSG_249), + LOC_CTRL(MSG_250), + LOC_CTRL(MSG_251), + LOC_CTRL(MSG_252), + LOC_CTRL(MSG_253), + LOC_CTRL(MSG_254), + LOC_CTRL(MSG_255), + LOC_CTRL(MSG_256), + LOC_CTRL(MSG_257), + LOC_CTRL(MSG_258), + LOC_CTRL(IDOK), + LOC_CTRL(IDCANCEL), + LOC_CTRL(IDABORT), + LOC_CTRL(IDRETRY), + LOC_CTRL(IDIGNORE), + LOC_CTRL(IDYES), + LOC_CTRL(IDNO), + LOC_CTRL(IDCLOSE), + LOC_CTRL(IDHELP), +}; + +// Dialog data +loc_dlg_list loc_dlg[] = { + LOC_DLG(IDD_DIALOG), + LOC_DLG(IDD_ABOUTBOX), + LOC_DLG(IDD_NOTIFICATION), + LOC_DLG(IDD_LICENSE), + LOC_DLG(IDD_ISO_EXTRACT), + LOC_DLG(IDD_LOG), + LOC_DLG(IDD_UPDATE_POLICY), + LOC_DLG(IDD_NEW_VERSION), + LOC_DLG(IDD_MESSAGES), +}; diff --git a/src/localization_data.sh b/src/localization_data.sh new file mode 100644 index 00000000..64f78465 --- /dev/null +++ b/src/localization_data.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +echo This file recreates localization_data.c according resource.h +echo + +# check that sed are available +type -P sed &>/dev/null || { echo "sed command not found. Aborting." >&2; exit 1; } + +# Create the first sed command file +cat > cmd.sed <<\_EOF +# Insert header +1i /*\ + * Rufus: The Reliable USB Formatting Utility\ + * Localization tables - autogenerated from resource.h\ + * Copyright © 2013 Pete Batard \ + *\ + * This program is free software: you can redistribute it and/or modify\ + * it under the terms of the GNU General Public License as published by\ + * the Free Software Foundation, either version 3 of the License, or\ + * (at your option) any later version.\ + *\ + * This program is distributed in the hope that it will be useful,\ + * but WITHOUT ANY WARRANTY; without even the implied warranty of\ + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\ + * GNU General Public License for more details.\ + *\ + * You should have received a copy of the GNU General Public License\ + * along with this program. If not, see .\ + */\ +\ +#include \ +#include "resource.h"\ +#include "localization.h"\ +\ +#define LOC_CTRL(x) { #x, x }\ +#define LOC_DLG(x) { x, NULL, {NULL, NULL} }\ +\ +// Control IDs\ +const loc_control_id control_id[] = {\ + // The dialog IDs must come first + +# Add the control entries - must be in IDD_, IDC_, IDS_ or MSG_ +s/^#define \([I|M][D|S][D|C|S|G]_[^ ]*\) .*/\ LOC_CTRL(\1),/ + +# Add standard IDs from windows.h and close table +$a\ + LOC_CTRL(IDOK),\ + LOC_CTRL(IDCANCEL),\ + LOC_CTRL(IDABORT),\ + LOC_CTRL(IDRETRY),\ + LOC_CTRL(IDIGNORE),\ + LOC_CTRL(IDYES),\ + LOC_CTRL(IDNO),\ + LOC_CTRL(IDCLOSE),\ + LOC_CTRL(IDHELP),\ +\};\ + +# Remove everything else +/^[#|\/]/d +/^$/d +_EOF + +# Run first part +sed -f cmd.sed resource.h > localization_data.h + +# Create the second sed command file +cat > cmd.sed <<\_EOF + +# Insert dialog table header +1i // Dialog data\ +loc_dlg_list loc_dlg[] = { + +# Add the dialog entries - must start with IDD_ +s/^#define \(IDD_[^ ]*\) .*/\ LOC_DLG(\1),/ + +# Close the table +$a\ +}; + +# Remove everything else +/^[#|\/]/d +/^$/d +_EOF + +# Run second part +sed -f cmd.sed resource.h >> localization_data.h + +rm cmd.sed +echo Done. diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h index 80dce69b..4a0d1ea9 100644 --- a/src/msapi_utf8.h +++ b/src/msapi_utf8.h @@ -1,6 +1,7 @@ /* * MSAPI_UTF8: Common API calls using UTF-8 strings * Compensating for what Microsoft should have done a long long time ago. + * Also see http://utf8everywhere.org/ * * Copyright © 2010-2013 Pete Batard * @@ -53,6 +54,15 @@ extern "C" { _ms_wlvi.pszText = utf8_to_wchar(pszText_); \ SNDMSG((hwndLV),LVM_SETITEMTEXTW,(WPARAM)(i),(LPARAM)&_ms_wlvi); sfree(_ms_wlvi.pszText);} +// Never ever use isdigit() or isspace(), etc. on UTF-8 strings! +// These calls take an int and char is signed so MS compilers will produce an assert error on anything that's > 0x80 +#define isasciiU(c) isascii((unsigned char)(c)) +#define iscntrlU(c) iscntrl((unsigned char)(c)) +#define isdigitU(c) isdigit((unsigned char)(c)) +#define isspaceU(c) isspace((unsigned char)(c)) +#define isxdigitU(c) isxdigit((unsigned char)(c)) +// NB: other issomething() calls are not implemented as they may require multibyte UTF-8 sequences to be converted + #define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0) #define wconvert(p) wchar_t* w ## p = utf8_to_wchar(p) #define walloc(p, size) wchar_t* w ## p = (wchar_t*)calloc(size, sizeof(wchar_t)) @@ -354,6 +364,38 @@ static __inline DWORD GetCurrentDirectoryU(DWORD nBufferLength, char* lpBuffer) return ret; } +static __inline DWORD GetTempPathU(DWORD nBufferLength, char* lpBuffer) +{ + DWORD ret = 0, err = ERROR_INVALID_DATA; + walloc(lpBuffer, nBufferLength); + ret = GetTempPathW(nBufferLength, wlpBuffer); + err = GetLastError(); + if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) { + err = GetLastError(); + } + wfree(lpBuffer); + SetLastError(err); + return ret; +} + +static __inline DWORD GetTempFileNameU(char* lpPathName, char* lpPrefixString, UINT uUnique, char* lpTempFileName) +{ + DWORD ret = 0, err = ERROR_INVALID_DATA; + wconvert(lpPathName); + wconvert(lpPrefixString); + walloc(lpTempFileName, MAX_PATH); + ret =GetTempFileNameW(wlpPathName, wlpPrefixString, uUnique, wlpTempFileName); + err = GetLastError(); + if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpTempFileName, lpTempFileName, MAX_PATH)) == 0)) { + err = GetLastError(); + } + wfree(lpTempFileName); + wfree(lpPrefixString); + wfree(lpPathName); + SetLastError(err); + return ret; +} + static __inline DWORD GetModuleFileNameU(HMODULE hModule, char* lpFilename, DWORD nSize) { DWORD ret = 0, err = ERROR_INVALID_DATA; diff --git a/src/net.c b/src/net.c index cc83c9e4..e06c3a6a 100644 --- a/src/net.c +++ b/src/net.c @@ -34,6 +34,7 @@ #include "rufus.h" #include "registry.h" #include "resource.h" +#include "localization.h" /* Maximum download chunk size, in bytes */ #define DOWNLOAD_BUFFER_SIZE 10240 @@ -89,6 +90,7 @@ const char* WinInetErrorString(void) if ((error_code < INTERNET_ERROR_BASE) || (error_code > INTERNET_ERROR_LAST)) return WindowsErrorString(); + // TODO: These should be localized on an ad-hoc basis switch(error_code) { case ERROR_INTERNET_OUT_OF_HANDLES: return "No more handles could be generated at this time."; @@ -263,7 +265,7 @@ BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog) SendMessage(hProgressDialog, UM_ISO_INIT, 0, 0); } - PrintStatus(0, FALSE, "Downloading %s: Connecting...\n", file); + PrintStatus(0, FALSE, lmprintf(MSG_240, file)); uprintf("Downloading %s from %s\n", file, url); if (!InternetCrackUrlA(url, (DWORD)safe_strlen(url), 0, &UrlParts)) { @@ -340,7 +342,7 @@ BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog) break; dwSize += dwDownloaded; SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize)/(1.0f*dwTotalSize))), 0); - PrintStatus(0, FALSE, "Downloading: %0.1f%%\n", (100.0f*dwSize)/(1.0f*dwTotalSize)); + PrintStatus(0, FALSE, lmprintf(MSG_241, (100.0f*dwSize)/(1.0f*dwTotalSize))); if (fwrite(buf, 1, dwDownloaded, fd) != dwDownloaded) { uprintf("Error writing file '%s': %s\n", file, WinInetErrorString()); goto out; @@ -362,10 +364,10 @@ out: if (fd != NULL) fclose(fd); if (!r) { _unlink(file); - PrintStatus(0, FALSE, "Failed to download file."); + PrintStatus(0, FALSE, lmprintf(MSG_242)); SetLastError(error_code); - MessageBoxA(hMainDialog, IS_ERROR(FormatStatus)?StrError(FormatStatus):WinInetErrorString(), - "File download", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, IS_ERROR(FormatStatus)?StrError(FormatStatus):WinInetErrorString(), + lmprintf(MSG_044), MB_OK|MB_ICONERROR); } if (hRequest) InternetCloseHandle(hRequest); if (hConnection) InternetCloseHandle(hConnection); @@ -456,7 +458,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param) } } - PrintStatus(3000, TRUE, "Checking for " APPLICATION_NAME " updates...\n"); + PrintStatus(3000, TRUE, lmprintf(MSG_243)); status++; // 1 if (!GetVersionExA(&os_version)) { @@ -600,15 +602,14 @@ out: if (hSession) InternetCloseHandle(hSession); switch(status) { case 1: - PrintStatus(3000, TRUE, "Updates: Unable to connect to the internet.\n"); + PrintStatus(3000, TRUE, lmprintf(MSG_244)); break; case 2: - PrintStatus(3000, TRUE, "Updates: Unable to access version data.\n"); + PrintStatus(3000, TRUE, lmprintf(MSG_245)); break; case 3: case 4: - PrintStatus(3000, FALSE, "%s new version of " APPLICATION_NAME " %s\n", - found_new_version?"A":"No", found_new_version?"is available!":"was found."); + PrintStatus(3000, FALSE, lmprintf(found_new_version?MSG_246:MSG_247)); default: break; } diff --git a/src/parser.c b/src/parser.c index 8d85afc5..2702f1c7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -33,13 +33,415 @@ #include "rufus.h" #include "msapi_utf8.h" +#include "localization.h" -// Parse a line of UTF-16 text and return the data if it matches the 'token' -// The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is -// modified by the parser +static const char space[] = " \t"; +static const wchar_t wspace[] = L" \t"; + +/* + * Fill a localization command buffer by parsing the line arguments + * The command is allocated and must be freed (by calling free_loc_cmd) + */ +static loc_cmd* get_loc_cmd(char c, char* line) { + size_t i, j, k, l, r, ti = 0, ii = 0; + char *endptr, *expected_endptr, *token; + loc_cmd* lcmd = NULL; + + for (j=0; j= ARRAYSIZE(parse_cmd)) { + luprint("unknown command"); + return NULL; + } + + lcmd = (loc_cmd*)calloc(sizeof(loc_cmd), 1); + if (lcmd == NULL) { + luprint("could not allocate command"); + return NULL; + } + lcmd->ctrl_id = -1; + lcmd->command = parse_cmd[j].cmd; + lcmd->line_nr = (uint16_t)loc_line_nr; + + i = 0; + for (k = 0; parse_cmd[j].arg_type[k] != 0; k++) { + // Skip leading spaces + i += strspn(&line[i], space); + r = i; + if (line[i] == 0) { + luprintf("missing parameter for command '%c'", parse_cmd[j].c); + goto err; + } + switch(parse_cmd[j].arg_type[k]) { + case 's': // quoted string + // search leading quote + if (line[i++] != '"') { + luprint("no start quote"); + goto err; + } + r = i; + // locate ending quote + while ((line[i] != 0) && ((line[i] != '"') || ((line[i] == '"') && (line[i-1] == '\\')))) { + if ((line[i] == '"') && (line[i-1] == '\\')) { + strcpy(&line[i-1], &line[i]); + } else { + i++; + } + } + if (line[i] == 0) { + luprint("no end quote"); + goto err; + } + line[i++] = 0; + lcmd->txt[ti++] = safe_strdup(&line[r]); + break; + case 'c': // control ID (single word) + while ((line[i] != 0) && (line[i] != space[0]) && (line[i] != space[1])) + i++; + if (line[i] != 0) + line[i++] = 0; + lcmd->txt[ti++] = safe_strdup(&line[r]); + break; + case 'i': // 32 bit signed integer + // allow commas or dots between values + if ((line[i] == ',') || (line[i] == '.')) { + i += strspn(&line[i+1], space); + r = i; + } + while ((line[i] != 0) && (line[i] != space[0]) && (line[i] != space[1]) + && (line[i] != ',') && (line[i] != '.')) + i++; + expected_endptr = &line[i]; + if (line[i] != 0) + line[i++] = 0; + lcmd->num[ii++] = (int32_t)strtol(&line[r], &endptr, 0); + if (endptr != expected_endptr) { + luprint("invalid integer"); + goto err; + } + break; + case 'u': // comma separated list of unsigned integers (to end of line) + // count the number of commas + lcmd->unum_size = 1; + for (l=i; line[l] != 0; l++) { + if (line[l] == ',') + lcmd->unum_size++; + } + lcmd->unum = (uint32_t*)malloc(lcmd->unum_size * sizeof(uint32_t)); + token = strtok(&line[i], ","); + for (l=0; (lunum_size) && (token != NULL); l++) { + lcmd->unum[l] = (int32_t)strtol(token, &endptr, 0); + token = strtok(NULL, ","); + } + if ((token != NULL) || (l != lcmd->unum_size)) { + luprint("internal error (unexpected number of numeric values)"); + goto err; + } + break; + default: + uprintf("localization: unhandled arg_type '%c'\n", parse_cmd[j].arg_type[k]); + goto err; + } + } + + return lcmd; + +err: + free_loc_cmd(lcmd); + return NULL; +} + +/* + * Parse an UTF-8 localization command line + */ +static void get_loc_data_line(char* line) +{ + size_t i; + loc_cmd* lcmd = NULL; + char t; + + if ((line == NULL) || (line[0] == 0)) + return; + + // Skip leading spaces + i = strspn(line, space); + + // Read token (NUL character will be read if EOL) + t = line[i++]; + if (t == '#') // Comment + return; + if ((t == 0) || ((line[i] != space[0]) && (line[i] != space[1]))) { + luprintf("syntax error: '%s'", line); + return; + } + + lcmd = get_loc_cmd(t, &line[i]); + + if ((lcmd != NULL) && (lcmd->command != LC_LOCALE)) + // TODO: check return value? + dispatch_loc_cmd(lcmd); + else + free_loc_cmd(lcmd); +} + +/* + * Open a localization file and store its file name, with special case + * when dealing with the embedded loc file. + */ +FILE* open_loc_file(const char* filename) +{ + FILE* fd = NULL; + wchar_t *wfilename = NULL; + const char* tmp_ext = ".tmp"; + + if (filename == NULL) + return NULL; + + if (loc_filename != embedded_loc_filename) { + safe_free(loc_filename); + } + if (safe_strcmp(tmp_ext, &filename[safe_strlen(filename)-4]) == 0) { + loc_filename = embedded_loc_filename; + } else { + loc_filename = safe_strdup(filename); + } + wfilename = utf8_to_wchar(filename); + if (wfilename == NULL) { + uprintf("localization: could not convert '%s' filename to UTF-16\n", filename); + goto out; + } + fd = _wfopen(wfilename, L"r"); + if (fd == NULL) { + uprintf("localization: could not open '%s'\n", filename); + } + +out: + safe_free(wfilename); + return fd; +} + +/* + * Parse a localization file, to construct the list of available locales. + * The locale file must be UTF-8 with NO BOM. + */ +BOOL get_supported_locales(const char* filename) +{ + FILE* fd = NULL; + BOOL r = FALSE; + char line[1024]; + size_t i; + loc_cmd *lcmd = NULL, *last_lcmd = NULL; + long end_of_block; + + fd = open_loc_file(filename); + if (fd == NULL) + goto out; + + loc_line_nr = 0; + line[0] = 0; + free_locale_list(); + do { + // adjust the last block + end_of_block = ftell(fd); + if (fgets(line, sizeof(line), fd) == NULL) + break; + loc_line_nr++; + // Skip leading spaces + i = strspn(line, space); + if (line[i] != 'l') + continue; + // line[i] is not NUL so i+1 is safe to access + lcmd = get_loc_cmd(line[i], &line[i+1]); + if ((lcmd == NULL) || (lcmd->command != LC_LOCALE)) { + free_loc_cmd(lcmd); + continue; + } + // we use num[0] and num[1] as block delimiter index for this locale in the file + if (last_lcmd != NULL) { + last_lcmd->num[1] = (int32_t)end_of_block; + } + lcmd->num[0] = (int32_t)ftell(fd); + // Add our locale command to the locale list + list_add_tail(&lcmd->list, &locale_list); + uprintf("localization: found locale '%s'\n", lcmd->txt[0]); + last_lcmd = lcmd; + } while (1); + if (last_lcmd != NULL) + last_lcmd->num[1] = (int32_t)ftell(fd); + r = !list_empty(&locale_list); + if (r == FALSE) + uprintf("localization: '%s' contains no locale sections\n", filename); + +out: + if (fd != NULL) + fclose(fd); + return r; +} + +/* + * Parse a locale section in a localization file (UTF-8, no BOM) + * NB: this call is reentrant for the "base" command support + */ +char* get_loc_data_file(const char* filename, long offset, long end_offset, int start_line) +{ + size_t bufsize = 1024; + static FILE* fd = NULL; + char *ret = NULL, *buf = NULL; + size_t i = 0; + int r = 0, line_nr_incr = 1; + int c = 0, eol_char = 0; + int old_loc_line_nr; + BOOL eol = FALSE, escape_sequence = FALSE, reentrant = (fd != NULL); + long cur_offset = -1; + + if (reentrant) { + // Called, from a 'b' command - no need to reopen the file, + // just save the current offset and current line number + cur_offset = ftell(fd); + old_loc_line_nr = loc_line_nr; + } else { + if ((filename == NULL) || (filename[0] == 0)) + return NULL; + free_dialog_list(); + fd = open_loc_file(filename); + if (fd == NULL) + goto out; + } + loc_line_nr = start_line; + buf = (char*) malloc(bufsize); + if (buf == NULL) { + uprintf("localization: could not allocate line buffer\n"); + goto out; + } + + fseek(fd, offset, SEEK_SET); + + do { // custom readline handling for string collation, realloc, line numbers, etc. + c = getc(fd); + switch(c) { + case EOF: + buf[i] = 0; + if (!eol) + loc_line_nr += line_nr_incr; + get_loc_data_line(buf); + goto out; + case '\r': + case '\n': + if (escape_sequence) { + escape_sequence = FALSE; + break; + } + // This assumes that the EOL sequence is always the same throughout the file + if (eol_char == 0) + eol_char = c; + if (c == eol_char) { + if (eol) { + line_nr_incr++; + } else { + loc_line_nr += line_nr_incr; + line_nr_incr = 1; + } + } + buf[i] = 0; + if (!eol) { + // Strip trailing spaces (for string collation) + for (r = ((int)i)-1; (r>0) && ((buf[r]==space[0])||(buf[r]==space[1])); r--); + if (r < 0) + r = 0; + eol = TRUE; + } + break; + case ' ': + case '\t': + if (escape_sequence) { + escape_sequence = FALSE; + break; + } + if (!eol) { + buf[i++] = (char)c; + } + break; + case '\\': + if (!escape_sequence) { + escape_sequence = TRUE; + break; + } + // fall through on escape sequence + default: + if (escape_sequence) { + switch (c) { + case 'n': // \n -> CRLF + buf[i++] = '\r'; + buf[i++] = '\n'; + break; + case '"': // \" carried as is + buf[i++] = '\\'; + buf[i++] = '"'; + break; + case '\\': + buf[i++] = '\\'; + break; + default: // ignore any other escape sequence + break; + } + escape_sequence = FALSE; + } else { + // Collate multiline strings + if ((eol) && (c == '"') && (buf[r] == '"')) { + i = r; + eol = FALSE; + break; + } + if (eol) { + get_loc_data_line(buf); + eol = FALSE; + i = 0; + r = 0; + } + buf[i++] = (char)c; + } + break; + } + if (ftell(fd) > end_offset) + goto out; + // Have at least 2 chars extra, for \r\n sequences + if (i >= bufsize-2) { + bufsize *= 2; + if (bufsize > 32768) { + uprintf("localization: requested line buffer is larger than 32K!\n"); + goto out; + } + buf = (char*) _reallocf(buf, bufsize); + if (buf == NULL) { + uprintf("localization: could not grow line buffer\n"); + goto out; + } + } + } while(1); + +out: + // Don't close on a reentrant call + if (reentrant) { + fseek(fd, cur_offset, SEEK_SET); + loc_line_nr = old_loc_line_nr; + } else if (fd != NULL) { + fclose(fd); + fd = NULL; + } + safe_free(buf); + return ret; +} + + +/* + * Parse a line of UTF-16 text and return the data if it matches the 'token' + * The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is + * modified by the parser + */ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline) { - const wchar_t wspace[] = L" \t"; // The only whitespaces we recognize as such size_t i, r; BOOLEAN quoteth = FALSE; @@ -90,8 +492,10 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline) return (wline[r] == 0)?NULL:&wline[r]; } -// Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the first occurrence of 'token' -// The returned string is UTF-8 and MUST be freed by the caller +/* + * Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the first occurrence of 'token' + * The returned string is UTF-8 and MUST be freed by the caller + */ char* get_token_data_file(const char* token, const char* filename) { wchar_t *wtoken = NULL, *wdata= NULL, *wfilename = NULL; @@ -135,8 +539,10 @@ out: return ret; } -// Parse a buffer (ANSI or UTF-8) and return the data for the 'n'th occurrence of 'token' -// The returned string is UTF-8 and MUST be freed by the caller +/* + * Parse a buffer (ANSI or UTF-8) and return the data for the 'n'th occurrence of 'token' + * The returned string is UTF-8 and MUST be freed by the caller + */ char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size) { unsigned int j, curly_count; @@ -199,10 +605,12 @@ static __inline char* get_sanitized_token_data_buffer(const char* token, unsigne return data; } -// Parse an update data file and populates a rufus_update structure. -// NB: since this is remote data, and we're running elevated, it *IS* considered -// potentially malicious, even if it comes from a supposedly trusted server. -// len should be the size of the buffer, including the zero terminator +/* + * Parse an update data file and populates a rufus_update structure. + * NB: since this is remote data, and we're running elevated, it *IS* considered + * potentially malicious, even if it comes from a supposedly trusted server. + * len should be the size of the buffer, including the zero terminator + */ void parse_update(char* buf, size_t len) { size_t i; @@ -249,13 +657,14 @@ void parse_update(char* buf, size_t len) update.release_notes = get_sanitized_token_data_buffer("release_notes", 1, buf, len); } -// Insert entry 'data' under section 'section' of a config file -// Section must include the relevant delimitors (eg '[', ']') if needed +/* + * Insert entry 'data' under section 'section' of a config file + * Section must include the relevant delimitors (eg '[', ']') if needed + */ char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix) { const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" }; wchar_t *wsection = NULL, *wfilename = NULL, *wtmpname = NULL, *wdata = NULL, bom = 0; - wchar_t wspace[] = L" \t"; wchar_t buf[1024]; FILE *fd_in = NULL, *fd_out = NULL; size_t i, size; @@ -316,7 +725,7 @@ char* insert_section_data(const char* filename, const char* section, const char* fd_out = _wfopen(wtmpname, outmode[mode]); if (fd_out == NULL) { - uprintf("Could not open temporary output file %s~\n", filename); + uprintf("Could not open temporary output file '%s~'\n", filename); goto out; } @@ -360,7 +769,7 @@ out: fclose(fd_in); fclose(fd_out); } else { - uprintf("Could not write %s - original file has been left unmodifiedn", filename); + uprintf("Could not write '%s' - original file has been left unmodified\n", filename); ret = NULL; if (fd_in != NULL) fclose(fd_in); if (fd_out != NULL) fclose(fd_out); @@ -375,15 +784,16 @@ out: return ret; } -// Search for a specific 'src' substring data for all occurrences of 'token', and replace -// it with 'rep'. File can be ANSI or UNICODE and is overwritten. Parameters are UTF-8. -// The parsed line is of the form: [ ]token[ ]data -// Returns a pointer to rep if replacement occurred, NULL otherwise +/* + * Search for a specific 'src' substring data for all occurrences of 'token', and replace + * it with 'rep'. File can be ANSI or UNICODE and is overwritten. Parameters are UTF-8. + * The parsed line is of the form: [ ]token[ ]data + * Returns a pointer to rep if replacement occurred, NULL otherwise + */ char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix) { const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" }; wchar_t *wtoken = NULL, *wfilename = NULL, *wtmpname = NULL, *wsrc = NULL, *wrep = NULL, bom = 0; - wchar_t wspace[] = L" \t"; wchar_t buf[1024], *torep; FILE *fd_in = NULL, *fd_out = NULL; size_t i, size; @@ -451,7 +861,7 @@ char* replace_in_token_data(const char* filename, const char* token, const char* fd_out = _wfopen(wtmpname, outmode[mode]); if (fd_out == NULL) { - uprintf("Could not open temporary output file %s~\n", filename); + uprintf("Could not open temporary output file '%s~'\n", filename); goto out; } @@ -506,7 +916,7 @@ out: fclose(fd_in); fclose(fd_out); } else { - uprintf("Could not write %s - original file has been left unmodified.\n", filename); + uprintf("Could not write '%s' - original file has been left unmodified.\n", filename); ret = NULL; if (fd_in != NULL) fclose(fd_in); if (fd_out != NULL) fclose(fd_out); diff --git a/src/resource.h b/src/resource.h index ef97e598..1b238dc9 100644 --- a/src/resource.h +++ b/src/resource.h @@ -3,17 +3,17 @@ // Used by rufus.rc // #define IDD_DIALOG 101 -#define IDI_ICON 102 -#define IDD_ABOUTBOX 103 -#define IDD_NOTIFICATION 104 -#define IDD_LICENSE 105 -#define IDD_ISO_EXTRACT 106 -#define IDD_LOG 107 -#define IDS_VERSION 108 -#define IDI_UP 109 -#define IDI_DOWN 110 -#define IDD_UPDATE_POLICY 111 -#define IDD_NEW_VERSION 112 +#define IDD_ABOUTBOX 102 +#define IDD_NOTIFICATION 103 +#define IDD_LICENSE 104 +#define IDD_ISO_EXTRACT 105 +#define IDD_LOG 106 +#define IDD_UPDATE_POLICY 107 +#define IDD_NEW_VERSION 108 +#define IDD_MESSAGES 109 +#define IDI_ICON 110 +#define IDI_UP 111 +#define IDI_DOWN 112 #define IDR_BR_MBR_BIN 200 #define IDR_FD_COMMAND_COM 300 #define IDR_FD_KERNEL_SYS 301 @@ -46,10 +46,11 @@ #define IDR_SL_LDLINUX_V4_SYS 401 #define IDR_SL_LDLINUX_V5_BSS 402 #define IDR_SL_LDLINUX_V5_SYS 403 +#define IDR_LC_RUFUS_LOC 500 #define IDC_DEVICE 1001 #define IDC_FILESYSTEM 1002 #define IDC_START 1003 -#define IDC_PARTITION_SCHEME 1004 +#define IDC_PARTITION_TYPE 1004 #define IDC_CLUSTERSIZE 1005 #define IDC_STATUS 1006 #define IDC_ABOUT 1007 @@ -79,7 +80,7 @@ #define IDC_NOTIFICATION_TEXT 1041 #define IDC_NOTIFICATION_LINE 1042 #define IDC_ADVANCED 1043 -#define IDC_ADVANCED_GROUP 1044 +#define IDS_ADVANCED_OPTIONS_GRP 1044 #define IDC_LOG 1045 #define IDC_LOG_EDIT 1050 #define IDC_LOG_SAVE 1051 @@ -95,15 +96,287 @@ #define IDC_YOUR_VERSION 1068 #define IDC_LATEST_VERSION 1069 #define IDC_DOWNLOAD_URL 1070 +#define IDS_DEVICE_TXT 2000 +#define IDS_PARTITION_TYPE_TXT 2001 +#define IDS_FILESYSTEM_TXT 2002 +#define IDS_CLUSTERSIZE_TXT 2003 +#define IDS_LABEL_TXT 2004 +#define IDS_FORMAT_OPTIONS_GRP 2005 +#define IDS_UPDATE_SETTINGS_GRP 2006 +#define IDS_UPDATE_FREQUENCY_TXT 2007 +#define IDS_INCLUDE_BETAS_TXT 2008 +#define IDS_NEW_VERSION_AVAIL_TXT 2009 +#define IDS_NEW_VERSION_DOWNLOAD_GRP 2010 +#define IDS_NEW_VERSION_NOTES_GRP 2011 +#define IDS_CHECK_NOW_GRP 2012 +#define MSG_000 3000 +#define MSG_001 3001 +#define MSG_002 3002 +#define MSG_003 3003 +#define MSG_004 3004 +#define MSG_005 3005 +#define MSG_006 3006 +#define MSG_007 3007 +#define MSG_008 3008 +#define MSG_009 3009 +#define MSG_010 3010 +#define MSG_011 3011 +#define MSG_012 3012 +#define MSG_013 3013 +#define MSG_014 3014 +#define MSG_015 3015 +#define MSG_016 3016 +#define MSG_017 3017 +#define MSG_018 3018 +#define MSG_019 3019 +#define MSG_020 3020 +#define MSG_021 3021 +#define MSG_022 3022 +#define MSG_023 3023 +#define MSG_024 3024 +#define MSG_025 3025 +#define MSG_026 3026 +#define MSG_027 3027 +#define MSG_028 3028 +#define MSG_029 3029 +#define MSG_030 3030 +#define MSG_031 3031 +#define MSG_032 3032 +#define MSG_033 3033 +#define MSG_034 3034 +#define MSG_035 3035 +#define MSG_036 3036 +#define MSG_037 3037 +#define MSG_038 3038 +#define MSG_039 3039 +#define MSG_040 3040 +#define MSG_041 3041 +#define MSG_042 3042 +#define MSG_043 3043 +#define MSG_044 3044 +#define MSG_045 3045 +#define MSG_046 3046 +#define MSG_047 3047 +#define MSG_048 3048 +#define MSG_049 3049 +#define MSG_050 3050 +#define MSG_051 3051 +#define MSG_052 3052 +#define MSG_053 3053 +#define MSG_054 3054 +#define MSG_055 3055 +#define MSG_056 3056 +#define MSG_057 3057 +#define MSG_058 3058 +#define MSG_059 3059 +#define MSG_060 3060 +#define MSG_061 3061 +#define MSG_062 3062 +#define MSG_063 3063 +#define MSG_064 3064 +#define MSG_065 3065 +#define MSG_066 3066 +#define MSG_067 3067 +#define MSG_068 3068 +#define MSG_069 3069 +#define MSG_070 3070 +#define MSG_071 3071 +#define MSG_072 3072 +#define MSG_073 3073 +#define MSG_074 3074 +#define MSG_075 3075 +#define MSG_076 3076 +#define MSG_077 3077 +#define MSG_078 3078 +#define MSG_079 3079 +#define MSG_080 3080 +#define MSG_081 3081 +#define MSG_082 3082 +#define MSG_083 3083 +#define MSG_084 3084 +#define MSG_085 3085 +#define MSG_086 3086 +#define MSG_087 3087 +#define MSG_088 3088 +#define MSG_089 3089 +#define MSG_090 3090 +#define MSG_091 3091 +#define MSG_092 3092 +#define MSG_093 3093 +#define MSG_094 3094 +#define MSG_095 3095 +#define MSG_096 3096 +#define MSG_097 3097 +#define MSG_098 3098 +#define MSG_099 3099 +#define MSG_100 3100 +#define MSG_101 3101 +#define MSG_102 3102 +#define MSG_103 3103 +#define MSG_104 3104 +#define MSG_105 3105 +#define MSG_106 3106 +#define MSG_107 3107 +#define MSG_108 3108 +#define MSG_109 3109 +#define MSG_110 3110 +#define MSG_111 3111 +#define MSG_112 3112 +#define MSG_113 3113 +#define MSG_114 3114 +#define MSG_115 3115 +#define MSG_116 3116 +#define MSG_117 3117 +#define MSG_118 3118 +#define MSG_119 3119 +#define MSG_120 3120 +#define MSG_121 3121 +#define MSG_122 3122 +#define MSG_123 3123 +#define MSG_124 3124 +#define MSG_125 3125 +#define MSG_126 3126 +#define MSG_127 3127 +#define MSG_128 3128 +#define MSG_129 3129 +#define MSG_130 3130 +#define MSG_131 3131 +#define MSG_132 3132 +#define MSG_133 3133 +#define MSG_134 3134 +#define MSG_135 3135 +#define MSG_136 3136 +#define MSG_137 3137 +#define MSG_138 3138 +#define MSG_139 3139 +#define MSG_140 3140 +#define MSG_141 3141 +#define MSG_142 3142 +#define MSG_143 3143 +#define MSG_144 3144 +#define MSG_145 3145 +#define MSG_146 3146 +#define MSG_147 3147 +#define MSG_148 3148 +#define MSG_149 3149 +#define MSG_150 3150 +#define MSG_151 3151 +#define MSG_152 3152 +#define MSG_153 3153 +#define MSG_154 3154 +#define MSG_155 3155 +#define MSG_156 3156 +#define MSG_157 3157 +#define MSG_158 3158 +#define MSG_159 3159 +#define MSG_160 3160 +#define MSG_161 3161 +#define MSG_162 3162 +#define MSG_163 3163 +#define MSG_164 3164 +#define MSG_165 3165 +#define MSG_166 3166 +#define MSG_167 3167 +#define MSG_168 3168 +#define MSG_169 3169 +#define MSG_170 3170 +#define MSG_171 3171 +#define MSG_172 3172 +#define MSG_173 3173 +#define MSG_174 3174 +#define MSG_175 3175 +#define MSG_176 3176 +#define MSG_177 3177 +#define MSG_178 3178 +#define MSG_179 3179 +#define MSG_180 3180 +#define MSG_181 3181 +#define MSG_182 3182 +#define MSG_183 3183 +#define MSG_184 3184 +#define MSG_185 3185 +#define MSG_186 3186 +#define MSG_187 3187 +#define MSG_188 3188 +#define MSG_189 3189 +#define MSG_190 3190 +#define MSG_191 3191 +#define MSG_192 3192 +#define MSG_193 3193 +#define MSG_194 3194 +#define MSG_195 3195 +#define MSG_196 3196 +#define MSG_197 3197 +#define MSG_198 3198 +#define MSG_199 3199 +#define MSG_200 3200 +#define MSG_201 3201 +#define MSG_202 3202 +#define MSG_203 3203 +#define MSG_204 3204 +#define MSG_205 3205 +#define MSG_206 3206 +#define MSG_207 3207 +#define MSG_208 3208 +#define MSG_209 3209 +#define MSG_210 3210 +#define MSG_211 3211 +#define MSG_212 3212 +#define MSG_213 3213 +#define MSG_214 3214 +#define MSG_215 3215 +#define MSG_216 3216 +#define MSG_217 3217 +#define MSG_218 3218 +#define MSG_219 3219 +#define MSG_220 3220 +#define MSG_221 3221 +#define MSG_222 3222 +#define MSG_223 3223 +#define MSG_224 3224 +#define MSG_225 3225 +#define MSG_226 3226 +#define MSG_227 3227 +#define MSG_228 3228 +#define MSG_229 3229 +#define MSG_230 3230 +#define MSG_231 3231 +#define MSG_232 3232 +#define MSG_233 3233 +#define MSG_234 3234 +#define MSG_235 3235 +#define MSG_236 3236 +#define MSG_237 3237 +#define MSG_238 3238 +#define MSG_239 3239 +#define MSG_240 3240 +#define MSG_241 3241 +#define MSG_242 3242 +#define MSG_243 3243 +#define MSG_244 3244 +#define MSG_245 3245 +#define MSG_246 3246 +#define MSG_247 3247 +#define MSG_248 3248 +#define MSG_249 3249 +#define MSG_250 3250 +#define MSG_251 3251 +#define MSG_252 3252 +#define MSG_253 3253 +#define MSG_254 3254 +#define MSG_255 3255 +#define MSG_256 3256 +#define MSG_257 3257 +#define MSG_258 3258 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_RESOURCE_VALUE 404 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1071 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_SYMED_VALUE 4000 #endif #endif diff --git a/src/rufus.c b/src/rufus.c index a2e791b9..09c597cb 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -40,6 +40,7 @@ #include "resource.h" #include "rufus.h" #include "registry.h" +#include "localization.h" /* Redefinitions for WDK and MinGW */ #ifndef PBM_SETSTATE @@ -88,12 +89,6 @@ struct { const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "UDF", "exFAT" }; // Number of steps for each FS for FCC_STRUCTURE_PROGRESS const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10 }; -// Don't ask me - just following the MS "standard" here -// We hijack 256 as a "Default" for UDF, since we can't set clustersize there -static const char* ClusterSizeLabel[] = { "Default", "512 bytes", "1024 bytes","2048 bytes","4096 bytes","8192 bytes", - "16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes", - "1024 kilobytes","2048 kilobytes","4096 kilobytes","8192 kilobytes","16 megabytes","32 megabytes" }; -static const char* BiosTypeLabel[BT_MAX] = { "BIOS", "UEFI" }; static const char* PartitionTypeLabel[2] = { "MBR", "GPT" }; static BOOL existing_key = FALSE; // For LGP set/restore static BOOL size_check = TRUE; @@ -101,6 +96,8 @@ static BOOL log_displayed = FALSE; static BOOL iso_provided = FALSE; extern BOOL force_large_fat32, enable_joliet, enable_rockridge; static int selection_default; +static loc_cmd* selected_locale = NULL; +char ClusterSizeLabel[MAX_CLUSTER_SIZES][64]; char msgbox[1024], msgbox_title[32]; /* @@ -148,6 +145,23 @@ static float previous_end; #define MB 1048576LL #define GB 1073741824LL #define TB 1099511627776LL + +/* + * Fill in the cluster size names + */ +static void SetClusterSizeLabels(void) +{ + unsigned int i, j, k; + safe_sprintf(ClusterSizeLabel[0], 64, lmprintf(MSG_029)); + for (i=512, j=1, k=MSG_026; j 8192) { + i /= 1024; + k++; + } + safe_sprintf(ClusterSizeLabel[j], 64, "%d %s", i, lmprintf(k)); + } +} + /* * Set cluster size values according to http://support.microsoft.com/kb/140365 * this call will return FALSE if we can't find a supportable FS for the drive @@ -157,7 +171,7 @@ static BOOL DefineClusterSizes(void) LONGLONG i; int fs; BOOL r = FALSE; - char tmp[64] = ""; + char tmp[64] = "", *entry; default_fs = FS_UNKNOWN; memset(&SelectedDrive.ClusterSize, 0, sizeof(SelectedDrive.ClusterSize)); @@ -278,11 +292,13 @@ out: safe_strcat(tmp, sizeof(tmp), "Large "); safe_strcat(tmp, sizeof(tmp), FileSystemLabel[fs]); if (default_fs == FS_UNKNOWN) { - safe_strcat(tmp, sizeof(tmp), " (Default)"); + entry = lmprintf(MSG_030, tmp); default_fs = fs; + } else { + entry = tmp; } IGNORE_RETVAL(ComboBox_SetItemData(hFileSystem, - ComboBox_AddStringU(hFileSystem, tmp), fs)); + ComboBox_AddStringU(hFileSystem, entry), fs)); r = TRUE; } } @@ -299,7 +315,7 @@ out: */ static BOOL SetClusterSizes(int FSType) { - char szClustSize[64]; + char* szClustSize; int i, k, default_index = 0; ULONG j; @@ -317,10 +333,11 @@ static BOOL SetClusterSizes(int FSType) for(i=0,j=0x100,k=0;j<0x10000000;i++,j<<=1) { if (j & SelectedDrive.ClusterSize[FSType].Allowed) { - safe_sprintf(szClustSize, sizeof(szClustSize), "%s", ClusterSizeLabel[i]); if (j == SelectedDrive.ClusterSize[FSType].Default) { - safe_strcat(szClustSize, sizeof(szClustSize), " (Default)"); + szClustSize = lmprintf(MSG_030, ClusterSizeLabel[i]); default_index = k; + } else { + szClustSize = ClusterSizeLabel[i]; } IGNORE_RETVAL(ComboBox_SetItemData(hClusterSize, ComboBox_AddStringU(hClusterSize, szClustSize), j)); k++; @@ -470,15 +487,12 @@ static void SetPartitionSchemeTooltip(void) bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); pt = GETPARTTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); if (bt == BT_BIOS) { - CreateTooltip(hPartitionScheme, "Usually the safest choice. If you have an UEFI computer and want to install " - "an OS in EFI mode however, you should select one of the options below", 15000); + CreateTooltip(hPartitionScheme, lmprintf(MSG_150), 15000); } else { if (pt == PARTITION_STYLE_MBR) { - CreateTooltip(hPartitionScheme, "Use this if you want to install an OS in EFI mode, but need to access " - "the USB content from Windows XP", 15000); + CreateTooltip(hPartitionScheme, lmprintf(MSG_151), 15000); } else { - CreateTooltip(hPartitionScheme, "The preferred option to install an OS in EFI mode and when " - "USB access is not required for Windows XP", 15000); + CreateTooltip(hPartitionScheme, lmprintf(MSG_152), 15000); } } } @@ -489,8 +503,6 @@ static void SetPartitionSchemeTooltip(void) static BOOL PopulateProperties(int ComboIndex) { double HumanReadableSize; - char capacity[64]; - static char* suffix[] = { "B", "KB", "MB", "GB", "TB", "PB"}; char no_label[] = STR_NO_LABEL; int i, j, pt, bt; @@ -510,7 +522,7 @@ static BOOL PopulateProperties(int ComboIndex) EnableBootOptions(TRUE); HumanReadableSize = (double)SelectedDrive.DiskSize; - for (i=1; i= ARRAYSIZE(suffix)) + if (i >= MAX_SIZE_SUFFIXES) uprintf("Could not populate partition scheme data\n"); if (SelectedDrive.PartitionType == PARTITION_STYLE_GPT) { j = 2; @@ -548,10 +560,10 @@ static BOOL PopulateProperties(int ComboIndex) // If we're beneath the tolerance, round proposed label to an integer, if not, show two decimal point if (fabs(HumanReadableSize / ceil(HumanReadableSize) - 1.0) < PROPOSEDLABEL_TOLERANCE) { safe_sprintf(SelectedDrive.proposed_label, sizeof(SelectedDrive.proposed_label), - "%0.0f%s", ceil(HumanReadableSize), suffix[i]); + "%0.0f%s", ceil(HumanReadableSize), lmprintf(MSG_020+i)); } else { safe_sprintf(SelectedDrive.proposed_label, sizeof(SelectedDrive.proposed_label), - "%0.2f%s", HumanReadableSize, suffix[i]); + "%0.2f%s", HumanReadableSize, lmprintf(MSG_020+i)); } // If no existing label is available and no ISO is selected, propose one according to the size (eg: "256MB", "8GB") @@ -584,9 +596,8 @@ static BOOL GetUSBDevices(DWORD devnum) LONG maxwidth = 0; RECT rect; char drive_letter; - char *label, entry[MAX_PATH], buffer[MAX_PATH]; + char *label, *entry, buffer[MAX_PATH]; const char* usbstor_name = "USBSTOR"; - const char* generic_friendly_name = "USB Storage Device (Generic)"; GUID _GUID_DEVINTERFACE_DISK = // only known to some... { 0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} }; @@ -617,7 +628,7 @@ static BOOL GetUSBDevices(DWORD devnum) &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString()); // We can afford a failure on this call - just replace the name - safe_strcpy(buffer, sizeof(buffer), generic_friendly_name); + safe_strcpy(buffer, sizeof(buffer), lmprintf(MSG_045)); } uprintf("Found device '%s'\n", buffer); @@ -684,7 +695,7 @@ static BOOL GetUSBDevices(DWORD devnum) StrArrayAdd(&DriveLabel, label); // Drive letter ' ' is returned for drives that don't have a volume assigned yet if (drive_letter == ' ') { - safe_sprintf(entry, sizeof(entry), "%s (Disk %d)", label, device_number.DeviceNumber); + entry = lmprintf(MSG_046, label, device_number.DeviceNumber); } else { if (drive_letter == app_dir[0]) { uprintf("Removing %c: from the list: This is the disk from which " APPLICATION_NAME " is running!\n", drive_letter); @@ -692,7 +703,7 @@ static BOOL GetUSBDevices(DWORD devnum) safe_free(devint_detail_data); break; } - safe_sprintf(entry, sizeof(entry), "%s (%c:)", label, drive_letter); + entry = lmprintf(MSG_047, label, drive_letter); } IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), device_number.DeviceNumber + DRIVE_INDEX_MIN)); @@ -850,7 +861,7 @@ void UpdateProgress(int op, float percent) static void EnableControls(BOOL bEnable) { EnableWindow(GetDlgItem(hMainDialog, IDC_DEVICE), bEnable); - EnableWindow(GetDlgItem(hMainDialog, IDC_PARTITION_SCHEME), bEnable); + EnableWindow(GetDlgItem(hMainDialog, IDC_PARTITION_TYPE), bEnable); EnableWindow(GetDlgItem(hMainDialog, IDC_FILESYSTEM), bEnable); EnableWindow(GetDlgItem(hMainDialog, IDC_CLUSTERSIZE), bEnable); EnableWindow(GetDlgItem(hMainDialog, IDC_LABEL), bEnable); @@ -864,7 +875,7 @@ static void EnableControls(BOOL bEnable) EnableWindow(GetDlgItem(hMainDialog, IDC_SET_ICON), bEnable); EnableWindow(GetDlgItem(hMainDialog, IDC_ADVANCED), bEnable); EnableWindow(GetDlgItem(hMainDialog, IDC_ENABLE_FIXED_DISKS), bEnable); - SetDlgItemTextA(hMainDialog, IDCANCEL, bEnable?"Close":"Cancel"); + SetDlgItemTextU(hMainDialog, IDCANCEL, lmprintf(bEnable?MSG_006:MSG_007)); } /* Callback for the log window */ @@ -878,6 +889,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: + apply_localization(IDD_LOG, hDlg); hLog = GetDlgItem(hDlg, IDC_LOG_EDIT); // Increase the size of our log textbox to MAX_LOG_SIZE (unsigned word) PostMessage(hLog, EM_LIMITTEXT, MAX_LOG_SIZE , 0); @@ -907,7 +919,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size); if (log_size != 0) { log_size--; // remove NUL terminator - filepath = FileDialog(TRUE, app_dir, "rufus.log", "log", "Rufus log"); + filepath = FileDialog(TRUE, app_dir, "rufus.log", "log", lmprintf(MSG_108)); if (filepath != NULL) { FileIO(TRUE, filepath, &log_buffer, &log_size); } @@ -920,6 +932,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_CLOSE: ShowWindow(hDlg, SW_HIDE); + reset_localization(IDD_LOG); log_displayed = FALSE; return TRUE; } @@ -960,14 +973,7 @@ static void CALLBACK BlockingTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD // A write or close operation hasn't made any progress since our last check user_notified = TRUE; uprintf("Blocking I/O operation detected\n"); - MessageBoxU(hMainDialog, - APPLICATION_NAME " detected that Windows is still flushing its internal buffers\n" - "onto the USB device.\n\n" - "Depending on the speed of your USB device, this operation may\n" - "take a long time to complete, especially for large files.\n\n" - "We recommend that you let Windows finish, to avoid corruption.\n" - "But if you grow tired of waiting, you can just unplug the device...", - RUFUS_BLOCKING_IO_TITLE, MB_OK|MB_ICONINFORMATION); + MessageBoxU(hMainDialog, lmprintf(MSG_080), lmprintf(MSG_048), MB_OK|MB_ICONINFORMATION); } else { last_iso_blocking_status = iso_blocking_status; } @@ -979,6 +985,7 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: + apply_localization(IDD_ISO_EXTRACT, hDlg); hISOProgressBar = GetDlgItem(hDlg, IDC_PROGRESS); hISOFileName = GetDlgItem(hDlg, IDC_ISO_FILENAME); // Use maximum granularity for the progress bar @@ -999,7 +1006,7 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) switch (LOWORD(wParam)) { case IDC_ISO_ABORT: FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; - PrintStatus(0, FALSE, "Cancelling - Please wait..."); + PrintStatus(0, FALSE, lmprintf(MSG_201)); uprintf("Cancelling (from ISO proc.)\n"); EnableWindow(GetDlgItem(hISOProgressDlg, IDC_ISO_ABORT), FALSE); if (format_thid != NULL) @@ -1027,10 +1034,10 @@ DWORD WINAPI ISOScanThread(LPVOID param) if (iso_path == NULL) goto out; - PrintStatus(0, TRUE, "Scanning ISO image...\n"); + PrintStatus(0, TRUE, lmprintf(MSG_202)); if (!ExtractISO(iso_path, "", TRUE)) { SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0); - PrintStatus(0, TRUE, "Failed to scan ISO image."); + PrintStatus(0, TRUE, lmprintf(MSG_203)); safe_free(iso_path); goto out; } @@ -1047,9 +1054,7 @@ DWORD WINAPI ISOScanThread(LPVOID param) } } if ((!iso_report.has_bootmgr) && (!iso_report.has_isolinux) && (!IS_WINPE(iso_report.winpe)) && (!iso_report.has_efi)) { - MessageBoxU(hMainDialog, "This version of " APPLICATION_NAME " only supports bootable ISOs\n" - "based on bootmgr/WinPE, isolinux or EFI.\n" - "This ISO doesn't appear to use either...", "Unsupported ISO", MB_OK|MB_ICONINFORMATION); + MessageBoxU(hMainDialog, lmprintf(MSG_082), lmprintf(MSG_081), MB_OK|MB_ICONINFORMATION); safe_free(iso_path); SetMBRProps(); } else if (!iso_report.has_syslinux_v5) { // This check is for Syslinux v4.x or earlier @@ -1063,18 +1068,10 @@ DWORD WINAPI ISOScanThread(LPVOID param) fclose(fd); use_own_c32[i] = TRUE; } else { - PrintStatus(0, FALSE, "Obsolete %s detected", old_c32_name[i]); - safe_sprintf(msgbox, sizeof(msgbox), "This ISO image seems to use an obsolete version of '%s'.\n" - "Boot menus may not may not display properly because of this.\n\n" - "A newer version can be downloaded by " APPLICATION_NAME " to fix this issue:\n" - "- Choose 'Yes' to connect to the internet and download the file\n" - "- Choose 'No' to leave the existing ISO file unmodified\n" - "If you don't know what to do, you should select 'Yes'.\n\n" - "Note: The new file will be downloaded in the current directory and once a " - "'%s' exists there, it will be reused automatically.\n", old_c32_name[i], old_c32_name[i]); - safe_sprintf(msgbox_title, sizeof(msgbox_title), "Replace %s?", old_c32_name[i]); - if (MessageBoxU(hMainDialog, msgbox, msgbox_title, MB_YESNO|MB_ICONWARNING) == IDYES) { - SetWindowTextU(hISOProgressDlg, "Downloading file"); + PrintStatus(0, FALSE, lmprintf(MSG_204, old_c32_name[i])); + if (MessageBoxU(hMainDialog, lmprintf(MSG_084, old_c32_name[i], old_c32_name[i]), + lmprintf(MSG_083, old_c32_name[i]), MB_YESNO|MB_ICONWARNING) == IDYES) { + SetWindowTextU(hISOProgressDlg, lmprintf(MSG_085, old_c32_name[i])); SetWindowTextU(hISOFileName, new_c32_url[i]); if (DownloadFile(new_c32_url[i], old_c32_name[i], hISOProgressDlg)) use_own_c32[i] = TRUE; @@ -1088,7 +1085,7 @@ DWORD WINAPI ISOScanThread(LPVOID param) SetFSFromISO(); SetMBRProps(); for (i=(int)safe_strlen(iso_path); (i>0)&&(iso_path[i]!='\\'); i--); - PrintStatus(0, TRUE, "Using ISO: %s\n", &iso_path[i+1]); + PrintStatus(0, TRUE, lmprintf(MSG_205, &iso_path[i+1])); // Some Linux distros, such as Arch Linux, require the USB drive to have // a specific label => copy the one we got from the ISO image if (iso_report.label[0] != 0) { @@ -1105,28 +1102,17 @@ out: ExitThread(0); } -void MoveControl(HWND hDlg, int nID, float vertical_shift) -{ - RECT rect; - POINT point; - HWND hControl; - - hControl = GetDlgItem(hDlg, nID); - GetWindowRect(hControl, &rect); - point.x = rect.left; - point.y = rect.top; - ScreenToClient(hDlg, &point); - GetClientRect(hControl, &rect); - MoveWindow(hControl, point.x, point.y + (int)(fScale*(advanced_mode?vertical_shift:-vertical_shift)), - (rect.right - rect.left), (rect.bottom - rect.top), TRUE); +// Move a control along the Y axis according to the advanced mode setting +void MoveCtrlY(HWND hDlg, int nID, float vertical_shift) { + ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, nID), 0, + (int)(advanced_mode?vertical_shift:-vertical_shift), 0, 0); } void SetPassesTooltip(void) { - char passes_tooltip[32]; - safe_strcpy(passes_tooltip, sizeof(passes_tooltip), "Pattern: 0x55, 0xAA, 0xFF, 0x00"); - passes_tooltip[13 + ComboBox_GetCurSel(hNBPasses)*6] = 0; - CreateTooltip(hNBPasses, passes_tooltip, -1); + const unsigned char pattern[] = BADBLOCK_PATTERNS; + CreateTooltip(hNBPasses, lmprintf(MSG_153 + ComboBox_GetCurSel(hNBPasses), + pattern[0], pattern[1], pattern[2], pattern[3]), -1); } // Toggle "advanced" mode @@ -1147,14 +1133,14 @@ void ToggleAdvanced(void) point.y + (int)(fScale*(advanced_mode?dialog_shift:-dialog_shift)), TRUE); // Move the status bar up or down - MoveControl(hMainDialog, IDC_STATUS, dialog_shift); - MoveControl(hMainDialog, IDC_START, dialog_shift); - MoveControl(hMainDialog, IDC_PROGRESS, dialog_shift); - MoveControl(hMainDialog, IDC_ABOUT, dialog_shift); - MoveControl(hMainDialog, IDC_LOG, dialog_shift); - MoveControl(hMainDialog, IDCANCEL, dialog_shift); + MoveCtrlY(hMainDialog, IDC_STATUS, dialog_shift); + MoveCtrlY(hMainDialog, IDC_START, dialog_shift); + MoveCtrlY(hMainDialog, IDC_PROGRESS, dialog_shift); + MoveCtrlY(hMainDialog, IDC_ABOUT, dialog_shift); + MoveCtrlY(hMainDialog, IDC_LOG, dialog_shift); + MoveCtrlY(hMainDialog, IDCANCEL, dialog_shift); #ifdef RUFUS_TEST - MoveControl(hMainDialogm, IDC_TEST, dialog_shift); + MoveCtrlY(hMainDialog, IDC_TEST, dialog_shift); #endif // And do the same for the log dialog while we're at it @@ -1163,9 +1149,9 @@ void ToggleAdvanced(void) point.y = (rect.bottom - rect.top); MoveWindow(hLogDlg, rect.left, rect.top, point.x, point.y + (int)(fScale*(advanced_mode?dialog_shift:-dialog_shift)), TRUE); - MoveControl(hLogDlg, IDC_LOG_CLEAR, dialog_shift); - MoveControl(hLogDlg, IDC_LOG_SAVE, dialog_shift); - MoveControl(hLogDlg, IDCANCEL, dialog_shift); + MoveCtrlY(hLogDlg, IDC_LOG_CLEAR, dialog_shift); + MoveCtrlY(hLogDlg, IDC_LOG_SAVE, dialog_shift); + MoveCtrlY(hLogDlg, IDCANCEL, dialog_shift); GetWindowRect(hLog, &rect); point.x = (rect.right - rect.left); point.y = (rect.bottom - rect.top) + (int)(fScale*(advanced_mode?dialog_shift:-dialog_shift)); @@ -1179,7 +1165,7 @@ void ToggleAdvanced(void) ShowWindow(GetDlgItem(hMainDialog, IDC_EXTRA_PARTITION), toggle); ShowWindow(GetDlgItem(hMainDialog, IDC_RUFUS_MBR), toggle); ShowWindow(GetDlgItem(hMainDialog, IDC_DISK_ID), toggle); - ShowWindow(GetDlgItem(hMainDialog, IDC_ADVANCED_GROUP), toggle); + ShowWindow(GetDlgItem(hMainDialog, IDS_ADVANCED_OPTIONS_GRP), toggle); // Toggle the up/down icon SendMessage(GetDlgItem(hMainDialog, IDC_ADVANCED), BCM_SETIMAGELIST, 0, (LPARAM)(advanced_mode?&bi_up:&bi_down)); @@ -1189,89 +1175,67 @@ static BOOL BootCheck(void) { int fs, bt, dt, r; FILE* fd; - const char* ldlinux_c32 = "ldlinux.c32"; + const char* ldlinux_name = "ldlinux.c32"; dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); if (dt == DT_ISO) { if (iso_path == NULL) { - MessageBoxU(hMainDialog, "Please click on the disc button to select a bootable ISO,\n" - "or uncheck the \"Create a bootable disk...\" checkbox.", - "No ISO image selected", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_087), lmprintf(MSG_086), MB_OK|MB_ICONERROR); return FALSE; } if ((size_check) && (iso_report.projected_size > (uint64_t)SelectedDrive.DiskSize)) { - MessageBoxU(hMainDialog, "This ISO image is too big " - "for the selected target.", "ISO image too big", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_089), lmprintf(MSG_088), MB_OK|MB_ICONERROR); return FALSE; } fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme))); if (bt == BT_UEFI) { if (!IS_EFI(iso_report)) { - MessageBoxU(hMainDialog, "When using UEFI Target Type, only EFI bootable ISO images are supported. " - "Please select an EFI bootable ISO or set the Target Type to BIOS.", "Unsupported ISO", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_091), lmprintf(MSG_090), MB_OK|MB_ICONERROR); return FALSE; } else if (fs > FS_FAT32) { - MessageBoxU(hMainDialog, "When using UEFI Target Type, only FAT/FAT32 is supported. " - "Please select FAT/FAT32 as the File system or set the Target Type to BIOS.", "Unsupported filesystem", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_093), lmprintf(MSG_092), MB_OK|MB_ICONERROR); return FALSE; } else if (iso_report.has_4GB_file) { // Who the heck decided that using FAT32 for UEFI boot was a great idea?!? - MessageBoxU(hMainDialog, "This ISO image contains a file larger than 4 GB and cannot be used to create an EFI bootable USB.\r\n" - "This is a limitation from UEFI/FAT32, not from " APPLICATION_NAME ".", - "Non UEFI compatible ISO", MB_OK|MB_ICONINFORMATION); + MessageBoxU(hMainDialog, lmprintf(MSG_095), lmprintf(MSG_094), MB_OK|MB_ICONINFORMATION); return FALSE; } } else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe))) { if (iso_report.has_isolinux) { - MessageBoxU(hMainDialog, "Only FAT/FAT32 is supported for this type of ISO. " - "Please select FAT/FAT32 as the File system.", "Unsupported filesystem", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK|MB_ICONERROR); } else { - MessageBoxU(hMainDialog, "Only 'bootmgr' or 'WinPE' based ISO " - "images can currently be used with NTFS.", "Unsupported ISO", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_097), lmprintf(MSG_090), MB_OK|MB_ICONERROR); } return FALSE; } else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (!iso_report.has_isolinux)) { - MessageBoxU(hMainDialog, "FAT/FAT32 can only be used for isolinux based ISO images " - "or when the Target Type is UEFI.", "Unsupported ISO", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_098), lmprintf(MSG_090), MB_OK|MB_ICONERROR); return FALSE; } else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (iso_report.has_4GB_file)) { - MessageBoxU(hMainDialog, "This iso image contains a file larger than 4GB file, which is more than the " - "maximum size allowed for a FAT or FAT32 file system.", "Filesystem limitation", MB_OK|MB_ICONERROR); + MessageBoxU(hMainDialog, lmprintf(MSG_100), lmprintf(MSG_099), MB_OK|MB_ICONERROR); return FALSE; } if ((bt == BT_UEFI) && (iso_report.has_win7_efi) && (!WimExtractCheck())) { - if (MessageBoxU(hMainDialog, "Your platform cannot extract files from WIM archives. WIM extraction " - "is required to create EFI bootable Windows 7 and Windows Vista USB drives. You can fix that " - "by installing a recent version of 7-Zip.\r\nDo you want to visit the 7-zip download page?", - "Missing WIM support", MB_YESNO|MB_ICONERROR) == IDYES) + if (MessageBoxU(hMainDialog, lmprintf(MSG_102), lmprintf(MSG_101), MB_YESNO|MB_ICONERROR) == IDYES) ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL); return FALSE; } } else if (dt == DT_SYSLINUX_V5) { _chdirU(app_dir); - fd = fopen(ldlinux_c32, "rb"); + fd = fopen(ldlinux_name, "rb"); if (fd != NULL) { - uprintf("Will reuse '%s' for Syslinux v5\n", ldlinux_c32); + uprintf("Will reuse '%s' for Syslinux v5\n", ldlinux_name); fclose(fd); } else { - PrintStatus(0, FALSE, "Missing '%s' file", ldlinux_c32); - safe_sprintf(msgbox, sizeof(msgbox), "Syslinux v5.0 or later requires a '%s' file to be installed.\n" - "Because this file is more than 100 KB in size, and always present on Syslinux v5+ ISO images, " - "it is not embedded in " APPLICATION_NAME ".\n\n" - APPLICATION_NAME " can download the missing file for you:\n" - "- Select 'Yes' to connect to the internet and download the file\n" - "- Select 'No' if you want to manually copy this file on the drive later\n\n" - "Note: The file will be downloaded in the current directory and once a " - "'%s' exists there, it will be reused automatically.\n", ldlinux_c32, ldlinux_c32); - safe_sprintf(msgbox_title, sizeof(msgbox_title), "Download %s?", ldlinux_c32); - r = MessageBoxU(hMainDialog, msgbox, msgbox_title, MB_YESNOCANCEL|MB_ICONWARNING); + PrintStatus(0, FALSE, lmprintf(MSG_206, ldlinux_name)); + r = MessageBoxU(hMainDialog, lmprintf(MSG_104, ldlinux_name, ldlinux_name), + lmprintf(MSG_103, ldlinux_name), MB_YESNOCANCEL|MB_ICONWARNING); if (r == IDCANCEL) return FALSE; if (r == IDYES) { - SetWindowTextU(hISOProgressDlg, "Downloading file..."); - SetWindowTextU(hISOFileName, ldlinux_c32); - DownloadFile(LDLINUX_C32_URL, ldlinux_c32, hISOProgressDlg); + SetWindowTextU(hISOProgressDlg, lmprintf(MSG_085, ldlinux_name)); + SetWindowTextU(hISOFileName, LDLINUX_C32_URL); + DownloadFile(LDLINUX_C32_URL, ldlinux_name, hISOProgressDlg); } } } @@ -1295,7 +1259,7 @@ void InitDialog(HWND hDlg) // Quite a burden to carry around as parameters hMainDialog = hDlg; hDeviceList = GetDlgItem(hDlg, IDC_DEVICE); - hPartitionScheme = GetDlgItem(hDlg, IDC_PARTITION_SCHEME); + hPartitionScheme = GetDlgItem(hDlg, IDC_PARTITION_TYPE); hFileSystem = GetDlgItem(hDlg, IDC_FILESYSTEM); hClusterSize = GetDlgItem(hDlg, IDC_CLUSTERSIZE); hLabel = GetDlgItem(hDlg, IDC_LABEL); @@ -1344,6 +1308,11 @@ void InitDialog(HWND hDlg) } uprintf("Windows version: %s %d-bit\n", PrintWindowsVersion(nWindowsVersion), is_x64?64:32); + // Detect the LCID + uprintf("LCID: 0x%04X\n", GetUserDefaultLCID()); + + SetClusterSizeLabels(); + // Prefer FreeDOS to MS-DOS selection_default = DT_FREEDOS; // Create the status line and initialize the taskbar icon for progress overlay @@ -1355,21 +1324,19 @@ void InitDialog(HWND hDlg) SendMessage(hProgress, PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000); // Fill up the passes for (i=0; i<4; i++) { - safe_sprintf(tmp, sizeof(tmp), "%d Pass%s", i+1, (i==0)?"":"es"); - IGNORE_RETVAL(ComboBox_AddStringU(hNBPasses, tmp)); + IGNORE_RETVAL(ComboBox_AddStringU(hNBPasses, lmprintf((i==0)?MSG_034:MSG_035, i+1))); } IGNORE_RETVAL(ComboBox_SetCurSel(hNBPasses, 1)); SetPassesTooltip(); // Fill up the DOS type dropdown IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "MS-DOS"), DT_WINME)); IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "FreeDOS"), DT_FREEDOS)); - IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "ISO Image"), DT_ISO)); + IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, lmprintf(MSG_036)), DT_ISO)); IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, selection_default)); // Fill up the MBR masqueraded disk IDs ("8 disks should be enough for anybody") - IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, "0x80 (default)"), 0x80)); + IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, lmprintf(MSG_030, "0x80")), 0x80)); for (i=1; i<=7; i++) { - sprintf(tmp, "0x%02x (%d%s disk)", 0x80+i, i+1, (i==1)?"nd":((i==2)?"rd":"th")); - IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, tmp), 0x80+i)); + IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, lmprintf(MSG_109, 0x80+i, i+1)), 0x80+i)); } IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0)); @@ -1413,26 +1380,23 @@ void InitDialog(HWND hDlg) SendMessage(GetDlgItem(hDlg, IDC_ADVANCED), BCM_SETIMAGELIST, 0, (LPARAM)&bi_down); // Set the various tooltips - CreateTooltip(hFileSystem, "Sets the target filesystem", -1); - CreateTooltip(hClusterSize, "Minimum size that each data block occupies", -1); - CreateTooltip(hLabel, "Use this field to set the drive label\nInternational characters are accepted", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_ADVANCED), "Toggle advanced options", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_BADBLOCKS), "Test the device for bad blocks using a byte pattern", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_QUICKFORMAT), "Unchek this box to use the \"slow\" format method", -1); - CreateTooltip(hBoot, "Check this box to make the USB drive bootable", -1); - CreateTooltip(hBootType, "Boot method", -1); - CreateTooltip(hSelectISO, "Click to select an ISO...", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_SET_ICON), "Check this box to allow the display of international labels " - "and set a device icon (creates an autorun.inf)", 10000); - CreateTooltip(GetDlgItem(hDlg, IDC_RUFUS_MBR), "Install an MBR that allows boot selection and can masquerade the BIOS USB drive ID", 10000); - CreateTooltip(hDiskID, "Try to masquerade first bootable USB drive (usually 0x80) as a different disk.\n" - "This should only be necessary for XP installation" , 10000); - CreateTooltip(GetDlgItem(hDlg, IDC_EXTRA_PARTITION), "Create an extra hidden partition and try to align partitions boundaries.\n" - "This can improve boot detection for older BIOSes", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_ENABLE_FIXED_DISKS), "Enable detection for disks not normally detected by " APPLICATION_NAME ". " - "USE AT YOUR OWN RISKS!!!", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_START), "Start the formatting operation.\nThis will DESTROY any data on the target!", -1); - CreateTooltip(GetDlgItem(hDlg, IDC_ABOUT), "Licensing information and credits", -1); + CreateTooltip(hFileSystem, lmprintf(MSG_157), -1); + CreateTooltip(hClusterSize, lmprintf(MSG_158), -1); + CreateTooltip(hLabel, lmprintf(MSG_159), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_ADVANCED), lmprintf(MSG_160), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_BADBLOCKS), lmprintf(MSG_161), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_QUICKFORMAT), lmprintf(MSG_162), -1); + CreateTooltip(hBoot, lmprintf(MSG_163), -1); + CreateTooltip(hBootType, lmprintf(MSG_164), -1); + CreateTooltip(hSelectISO, lmprintf(MSG_165), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_SET_ICON), lmprintf(MSG_166), 10000); + CreateTooltip(GetDlgItem(hDlg, IDC_RUFUS_MBR), lmprintf(MSG_167), 10000); + CreateTooltip(hDiskID, lmprintf(MSG_168), 10000); + CreateTooltip(GetDlgItem(hDlg, IDC_EXTRA_PARTITION), lmprintf(MSG_169), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_ENABLE_FIXED_DISKS), lmprintf(MSG_170), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_START), lmprintf(MSG_171), -1); + CreateTooltip(GetDlgItem(hDlg, IDC_ABOUT), lmprintf(MSG_172), -1); + // TODO: add new tooltips ToggleAdvanced(); // We start in advanced mode => go to basic mode @@ -1445,9 +1409,10 @@ void InitDialog(HWND hDlg) static void PrintStatus2000(const char* str, BOOL val) { - PrintStatus(2000, FALSE, "%s %s.", str, (val)?"enabled":"disabled"); + PrintStatus(2000, FALSE, (lmprintf((val)?MSG_250:MSG_251, str))); } + /* * Main dialog callback */ @@ -1456,9 +1421,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA DRAWITEMSTRUCT* pDI; POINT Point; RECT DialogRect, DesktopRect; - int nDeviceIndex, fs, bt, i, nWidth, nHeight; + int nDeviceIndex, fs, bt, i, nWidth, nHeight, nb_devices; static DWORD DeviceNum = 0, LastRefresh = 0; - char tmp[128], str[MAX_PATH]; + char tmp[128]; static UINT uBootChecked = BST_CHECKED, uQFChecked; static BOOL first_log_display = TRUE, user_changed_label = FALSE; @@ -1497,9 +1462,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; case WM_INITDIALOG: + apply_localization(IDD_DIALOG, hDlg); SetUpdateCheck(); // Create the log window (hidden) - hLogDlg = CreateDialogA(hMainInstance, MAKEINTRESOURCEA(IDD_LOG), hDlg, (DLGPROC)LogProc); + hLogDlg = CreateDialogW(hMainInstance, MAKEINTRESOURCEW(IDD_LOG), hDlg, (DLGPROC)LogProc); InitDialog(hDlg); GetUSBDevices(0); CheckForUpdates(FALSE); @@ -1533,13 +1499,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA EnableWindow(GetDlgItem(hISOProgressDlg, IDC_ISO_ABORT), FALSE); EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); if (format_thid != NULL) { - if (MessageBoxU(hMainDialog, "Cancelling may leave the device in an UNUSABLE state.\r\n" - "If you are sure you want to cancel, click YES. Otherwise, click NO.", - RUFUS_CANCELBOX_TITLE, MB_YESNO|MB_ICONWARNING) == IDYES) { + if (MessageBoxU(hMainDialog, lmprintf(MSG_105), lmprintf(MSG_049), + MB_YESNO|MB_ICONWARNING) == IDYES) { // Operation may have completed in the meantime if (format_thid != NULL) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; - PrintStatus(0, FALSE, "Cancelling - Please wait..."); + PrintStatus(0, FALSE, lmprintf(MSG_201)); uprintf("Cancelling (from main app)\n"); // Start a timer to detect blocking operations during ISO file extraction if (iso_blocking_status >= 0) { @@ -1606,8 +1571,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case IDC_DEVICE: if (HIWORD(wParam) != CBN_SELCHANGE) break; - PrintStatus(0, TRUE, "%d device%s found.", ComboBox_GetCount(hDeviceList), - (ComboBox_GetCount(hDeviceList)!=1)?"s":""); + nb_devices = ComboBox_GetCount(hDeviceList); + PrintStatus(0, TRUE, lmprintf((nb_devices==1)?MSG_208:MSG_209, nb_devices)); PopulateProperties(ComboBox_GetCurSel(hDeviceList)); SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM, ComboBox_GetCurSel(hFileSystem)); @@ -1617,7 +1582,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; SetPassesTooltip(); break; - case IDC_PARTITION_SCHEME: + case IDC_PARTITION_TYPE: if (HIWORD(wParam) != CBN_SELCHANGE) break; SetPartitionSchemeTooltip(); @@ -1673,7 +1638,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "MS-DOS"), DT_WINME)); IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "FreeDOS"), DT_FREEDOS)); } - IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "ISO Image"), DT_ISO)); + IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, lmprintf(MSG_036)), DT_ISO)); // If needed (advanced mode) also append a Syslinux option if ( (bt == BT_BIOS) && (((fs == FS_FAT16) || (fs == FS_FAT32)) && (advanced_mode)) ) { IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "Syslinux 4"), DT_SYSLINUX_V4)); @@ -1729,9 +1694,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA iso_provided = FALSE; // One off thing... } else { safe_free(iso_path); - iso_path = FileDialog(FALSE, NULL, "*.iso", "iso", "ISO Image"); + iso_path = FileDialog(FALSE, NULL, "*.iso", "iso", lmprintf(MSG_036)); if (iso_path == NULL) { - CreateTooltip(hSelectISO, "Click to select...", -1); + CreateTooltip(hSelectISO, lmprintf(MSG_173), -1); break; } } @@ -1750,7 +1715,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case IDC_ENABLE_FIXED_DISKS: if ((HIWORD(wParam)) == BN_CLICKED) { enable_fixed_disks = !enable_fixed_disks; - PrintStatus2000("Fixed disks detection", enable_fixed_disks); + PrintStatus2000(lmprintf(MSG_253), enable_fixed_disks); GetUSBDevices(0); } break; @@ -1773,9 +1738,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; } GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); - _snprintf(str, ARRAYSIZE(str), "WARNING: ALL DATA ON DEVICE '%s'\r\nWILL BE DESTROYED.\r\n" - "To continue with this operation, click OK. To quit click CANCEL.", tmp); - if (MessageBoxU(hMainDialog, str, APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING) == IDCANCEL) { + if (MessageBoxU(hMainDialog, lmprintf(MSG_003, tmp), + APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING) == IDCANCEL) { format_op_in_progress = FALSE; break; } @@ -1818,7 +1782,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // You'd think that Windows would let you instantiate a modeless dialog wherever // but you'd be wrong. It must be done in the main callback, hence the custom message. if (!IsWindow(hISOProgressDlg)) { - hISOProgressDlg = CreateDialogA(hMainInstance, MAKEINTRESOURCEA(IDD_ISO_EXTRACT), + hISOProgressDlg = CreateDialogW(hMainInstance, MAKEINTRESOURCEW(IDD_ISO_EXTRACT), hDlg, (DLGPROC)ISOProc); // The window is not visible by default but takes focus => restore it SetFocus(hDlg); @@ -1830,8 +1794,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // Stop the timer KillTimer(hMainDialog, TID_APP_TIMER); // Close the cancel MessageBox and Blocking notification if active - SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0); - SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_BLOCKING_IO_TITLE), WM_COMMAND, IDYES, 0); + SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), lmprintf(MSG_049)), WM_COMMAND, IDNO, 0); + SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), lmprintf(MSG_049)), WM_COMMAND, IDYES, 0); EnableWindow(GetDlgItem(hISOProgressDlg, IDC_ISO_ABORT), TRUE); EnableWindow(GetDlgItem(hMainDialog, IDCANCEL), TRUE); EnableControls(TRUE); @@ -1843,17 +1807,17 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA SendMessage(hProgress, PBM_SETPOS, (MAX_PROGRESS+1), 0); SendMessage(hProgress, PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000); SetTaskbarProgressState(TASKBAR_NOPROGRESS); - PrintStatus(0, FALSE, "DONE"); + PrintStatus(0, FALSE, lmprintf(MSG_210)); } else if (SCODE_CODE(FormatStatus) == ERROR_CANCELLED) { SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_PAUSED, 0); SetTaskbarProgressState(TASKBAR_PAUSED); - PrintStatus(0, FALSE, "Cancelled"); - Notification(MSG_INFO, NULL, "Cancelled", "Operation cancelled by the user."); + PrintStatus(0, FALSE, lmprintf(MSG_211)); + Notification(MSG_INFO, NULL, lmprintf(MSG_211), lmprintf(MSG_041)); } else { SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_ERROR, 0); SetTaskbarProgressState(TASKBAR_ERROR); - PrintStatus(0, FALSE, "FAILED"); - Notification(MSG_ERROR, NULL, "Error", "Error: %s", StrError(FormatStatus)); + PrintStatus(0, FALSE, lmprintf(MSG_212)); + Notification(MSG_ERROR, NULL, lmprintf(MSG_042), lmprintf(MSG_043), StrError(FormatStatus)); } FormatStatus = 0; format_op_in_progress = FALSE; @@ -1912,10 +1876,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine const char* old_wait_option = "/W"; int i, opt, option_index = 0, argc = 0, si = 0; BOOL attached_console = FALSE; + BYTE* loc_data; + DWORD loc_size, Size; + char tmp_path[MAX_PATH], loc_file[MAX_PATH] = "", *locale_name = NULL; char** argv = NULL; wchar_t **wenv, **wargv; PF_DECL(__wgetmainargs); - HANDLE mutex = NULL; + HANDLE mutex = NULL, hFile = NULL; HWND hDlg = NULL; MSG msg; int wait_for_mutex = 0; @@ -1938,7 +1905,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine printf("\n"); } - // We have to process the arguments before we acquire the lock + // We have to process the arguments before we acquire the lock and process the locale PF_INIT(__wgetmainargs, msvcrt); if (pf__wgetmainargs != NULL) { pf__wgetmainargs(&argc, &wargv, &wenv, 1, &si); @@ -1950,7 +1917,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine wait_for_mutex = 150; // Try to acquire the mutex for 15 seconds } - while ((opt = getopt_long(argc, argv, "?fhi:w:", long_options, &option_index)) != EOF) + while ((opt = getopt_long(argc, argv, "?fhi:w:l:", long_options, &option_index)) != EOF) switch (opt) { case 'f': enable_fixed_disks = TRUE; @@ -1963,6 +1930,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine printf("Could not find ISO image '%s'\n", optarg); } break; + case 'l': + // TODO: accept a locale code such as 0x409 + locale_name = optarg; + break; case 'w': wait_for_mutex = atoi(optarg); break; @@ -1976,6 +1947,44 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine uprintf("unable to access UTF-16 args"); } + // Retrieve the current application directory + GetCurrentDirectoryU(MAX_PATH, app_dir); + + // Init localization + init_localization(); + // Seek for a loc file in the current directory + if (GetFileAttributesU("rufus.loc") == INVALID_FILE_ATTRIBUTES) { + uprintf("loc file not found in current directory - embedded one will be used"); + + loc_data = (BYTE*)GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_LC_RUFUS_LOC), _RT_RCDATA, "rufus.loc", &loc_size, FALSE); + GetTempPathU(sizeof(tmp_path), tmp_path); + GetTempFileNameU(tmp_path, APPLICATION_NAME, 0, loc_file); + + hFile = CreateFileU(loc_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, 0, 0); + if ((hFile == INVALID_HANDLE_VALUE)|| (!WriteFile(hFile, loc_data, loc_size, &Size, 0)) || (loc_size != Size)) { + safe_closehandle(hFile); + uprintf("localization: unable to extract '%s': %s.\n", loc_file, WindowsErrorString()); + } else { + safe_closehandle(hFile); + uprintf("localization: extracted data to '%s'\n", loc_file); + } + } else { + safe_sprintf(loc_file, sizeof(loc_file), "%s\\rufus.loc", app_dir); + uprintf("using external loc file '%s'", loc_file); + } + + if ( (!get_supported_locales(loc_file)) + || ((selected_locale = ((locale_name == NULL)?get_locale_from_lcid(GetUserDefaultLCID()):get_locale_from_name(locale_name))) == NULL) ) { + uprintf("FATAL: Could not access locale!\n"); + MessageBoxU(NULL, "The locale data is missing. This application will now exit.", + "Fatal error", MB_ICONSTOP); + goto out; + } + uprintf("localization: using locale '%s'\n", selected_locale->txt[0]); + get_loc_data_file(loc_file, (long)selected_locale->num[0], (long)selected_locale->num[1], selected_locale->line_nr); + + // Prevent 2 applications from running at the same time, unless "/W" is passed as an option // in which case we wait for the mutex to be relinquished if ((safe_strlen(lpCmdLine)==2) && (lpCmdLine[0] == '/') && (lpCmdLine[1] == 'W')) @@ -1987,9 +1996,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine mutex = CreateMutexA(NULL, TRUE, "Global/" APPLICATION_NAME); } if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS)) { - MessageBoxU(NULL, "Another " APPLICATION_NAME " application is running.\n" - "Please close the first application before running another one.", - "Other instance detected", MB_ICONSTOP); + MessageBoxU(NULL, lmprintf(MSG_002), lmprintf(MSG_001), MB_ICONSTOP); goto out; } @@ -2004,9 +2011,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine uprintf("Could not load RichEdit library - some dialogs may not display: %s\n", WindowsErrorString()); } - // Retrieve the current application directory - GetCurrentDirectoryU(MAX_PATH, app_dir); - // Set the Windows version nWindowsVersion = DetectWindowsVersion(); @@ -2015,7 +2019,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine SetLGP(FALSE, &existing_key, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDriveTypeAutorun", 0x9e); // Create the main Window - if ( (hDlg = CreateDialogA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG), NULL, MainCallback)) == NULL ) { + hDlg = CreateDialogW(hInstance, MAKEINTRESOURCEW(IDD_DIALOG), NULL, MainCallback); + if (hDlg == NULL) { MessageBoxU(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP); goto out; } @@ -2031,7 +2036,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // the target USB drive. If this is enabled, the size check is disabled. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) { size_check = !size_check; - PrintStatus2000("Size checks", size_check); + PrintStatus2000(lmprintf(MSG_252), size_check); GetUSBDevices(0); continue; } @@ -2041,20 +2046,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // drive instead of an USB key. If this is enabled, Rufus will allow fixed disk formatting. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) { enable_fixed_disks = !enable_fixed_disks; - PrintStatus2000("Fixed disks detection", enable_fixed_disks); + PrintStatus2000(lmprintf(MSG_253), enable_fixed_disks); GetUSBDevices(0); continue; } // Alt-L => Force Large FAT32 format to be used on < 32 GB drives if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) { force_large_fat32 = !force_large_fat32; - PrintStatus2000("Force large FAT32 usage", force_large_fat32); + PrintStatus2000(lmprintf(MSG_254), force_large_fat32); continue; } // Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed) // This key is used to disable Windows popup messages when an USB drive is plugged in. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) { - PrintStatus(2000, FALSE, "NoDriveTypeAutorun will be deleted on exit."); + PrintStatus(2000, FALSE, lmprintf(MSG_255)); existing_key = FALSE; continue; } @@ -2064,13 +2069,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // a file name). This option allows users to ignore Joliet when using such images. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'J')) { enable_joliet = !enable_joliet; - PrintStatus2000("Joliet support", enable_joliet); + PrintStatus2000(lmprintf(MSG_257), enable_joliet); continue; } - // Alt K => Toggle Rock Ridge support for ISO9660 image + // Alt K => Toggle Rock Ridge support for ISO9660 images if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'K')) { enable_rockridge = !enable_rockridge; - PrintStatus2000("Rock Ridge support", enable_rockridge); + PrintStatus2000(lmprintf(MSG_258), enable_rockridge); continue; } // Alt L => Toggle fake drive detection during bad blocks check @@ -2080,13 +2085,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // it back during the bad block check. if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) { detect_fakes = !detect_fakes; - PrintStatus2000("Fake drive detection", detect_fakes); + PrintStatus2000(lmprintf(MSG_256), detect_fakes); continue; } // Alt-R => Remove all the registry keys created by Rufus if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) { - PrintStatus(2000, FALSE, "Application registry key %s deleted.", - DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME)?"successfully":"could not be"); + PrintStatus(2000, FALSE, lmprintf(DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME)?MSG_248:MSG_249)); // Also try to delete the upper key (company name) if it's empty (don't care about the result) DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME); continue; @@ -2097,7 +2101,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } out: + if (loc_file[0] != 0) + DeleteFileU(loc_file); DestroyAllTooltips(); + exit_localization(); safe_free(iso_path); safe_free(update.download_url); safe_free(update.release_notes); diff --git a/src/rufus.h b/src/rufus.h index b0ba811a..3d969187 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -17,6 +17,7 @@ */ #include #include // for DISK_GEOMETRY +#include #include #if defined(_MSC_VER) @@ -29,19 +30,19 @@ /* Program options */ #define RUFUS_DEBUG // print debug info to Debug facility /* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS! */ -//#define RUFUS_TEST +// #define RUFUS_TEST #define APPLICATION_NAME "Rufus" #define COMPANY_NAME "Akeo Consulting" #define STR_NO_LABEL "NO_LABEL" -#define RUFUS_CANCELBOX_TITLE APPLICATION_NAME " - Cancellation" -#define RUFUS_BLOCKING_IO_TITLE APPLICATION_NAME " - Flushing buffers" #define DRIVE_ACCESS_TIMEOUT 15000 // How long we should retry drive access (in ms) #define DRIVE_ACCESS_RETRIES 60 // How many times we should retry #define DRIVE_INDEX_MIN 0x00000080 #define DRIVE_INDEX_MAX 0x000000C0 #define MAX_DRIVES (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN) -#define MAX_TOOLTIPS 32 +#define MAX_TOOLTIPS 128 +#define MAX_SIZE_SUFFIXES 6 // bytes, KB, MB, GB, TB, PB +#define MAX_CLUSTER_SIZES 18 #define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround #define MAX_LOG_SIZE 0x7FFFFFFE #define MAX_GUID_STRING_LENGTH 40 @@ -50,6 +51,7 @@ #define MBR_UEFI_MARKER 0x49464555 // 'U', 'E', 'F', 'I', as a 32 bit little endian longword #define PROPOSEDLABEL_TOLERANCE 0.10 #define FS_DEFAULT FS_FAT32 +#define BADBLOCK_PATTERNS {0xaa, 0x55, 0xff, 0x00} #define LARGE_FAT32_SIZE (32*1073741824LL) // Size at which we need to use fat32format #define MAX_FAT32_SIZE 2.0f // Threshold above which we disable FAT32 formatting (in TB) #define WHITE RGB(255,255,255) @@ -283,12 +285,13 @@ extern enum WindowsVersion DetectWindowsVersion(void); extern const char* PrintWindowsVersion(enum WindowsVersion version); extern const char *WindowsErrorString(void); extern void DumpBufferHex(void *buf, size_t size); -extern void PrintStatus(unsigned int duration, BOOL debug, const char *format, ...); +extern void PrintStatus(unsigned int duration, BOOL debug, const char* message); extern void UpdateProgress(int op, float percent); extern const char* StrError(DWORD error_code); extern char* GuidToString(const GUID* guid); extern char* SizeToHumanReadable(LARGE_INTEGER size); extern void CenterDialog(HWND hDlg); +extern void ResizeMoveCtrl(HWND hDlg, HWND hCtrl, int dx, int dy, int dw, int dh); extern void CreateStatusBar(void); extern void SetTitleBarIcon(HWND hDlg); extern BOOL CreateTaskbarList(void); @@ -342,12 +345,20 @@ extern void parse_update(char* buf, size_t len); extern BOOL WimExtractCheck(void); extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); -__inline static BOOL UnlockDrive(HANDLE hDrive) +static __inline BOOL UnlockDrive(HANDLE hDrive) { DWORD size; return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); } +static __inline void *_reallocf(void *ptr, size_t size) +{ + void *ret = realloc(ptr, size); + if (!ret) + free(ptr); + return ret; +} + /* Basic String Array */ typedef struct { char** Table; diff --git a/src/rufus.rc b/src/rufus.rc index e8dedcf5..b91d7f6b 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -30,48 +30,48 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 329 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.4.0.280" +CAPTION "Rufus v1.4.0.281" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 PUSHBUTTON "Close",IDCANCEL,148,291,50,14 - COMBOBOX IDC_DEVICE,8,17,190,33,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Device",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,9,6,22,8 - COMBOBOX IDC_FILESYSTEM,8,75,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "File system",IDC_STATIC,9,64,51,10 - COMBOBOX IDC_PARTITION_SCHEME,8,46,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Partition scheme and target system type",IDC_STATIC,9,35,176,8 - COMBOBOX IDC_CLUSTERSIZE,8,104,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Cluster size",IDC_STATIC,9,93,105,10 PUSHBUTTON "About...",IDC_ABOUT,8,291,50,14 - GROUPBOX "Format Options ",IDC_STATIC,7,149,192,66 + PUSHBUTTON "Log",IDC_LOG,62,291,18,14 + PUSHBUTTON "T",IDC_TEST,80,291,12,14,NOT WS_VISIBLE + COMBOBOX IDC_DEVICE,8,17,190,33,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Device",IDS_DEVICE_TXT,9,6,186,8 + COMBOBOX IDC_FILESYSTEM,8,75,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "File system",IDS_FILESYSTEM_TXT,9,64,186,10 + COMBOBOX IDC_PARTITION_TYPE,8,46,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Partition scheme and target system type",IDS_PARTITION_TYPE_TXT,9,35,186,8 + COMBOBOX IDC_CLUSTERSIZE,8,104,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Cluster size",IDS_CLUSTERSIZE_TXT,9,93,186,10 + GROUPBOX "Format Options ",IDS_FORMAT_OPTIONS_GRP,7,149,192,66 + LTEXT "New volume label",IDS_LABEL_TXT,9,121,186,10 EDITTEXT IDC_LABEL,7,131,190,13,ES_AUTOHSCROLL CONTROL "Check device for bad blocks:",IDC_BADBLOCKS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,161,101,10 - CONTROL "Quick format",IDC_QUICKFORMAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,173,55,10 + CONTROL "Quick format",IDC_QUICKFORMAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,173,181,10 CONTROL "Create a bootable disk using:",IDC_BOOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,185,104,10 CONTROL "Create extended label and icon files",IDC_SET_ICON, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,198,131,10 - LTEXT "New volume label",IDC_STATIC,9,121,105,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,198,181,10 CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,8,272,189,9 COMBOBOX IDC_NBPASSES,119,159,49,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_BOOTTYPE,119,183,49,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "...",IDC_SELECT_ISO,171,182,22,14,BS_ICON - PUSHBUTTON "T",IDC_TEST,80,291,12,14,NOT WS_VISIBLE - CONTROL "Use Rufus MBR with BIOS ID:",IDC_RUFUS_MBR,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,13,248,106,10 + CONTROL "Use Rufus MBR with BIOS ID:",IDC_RUFUS_MBR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,248,106,10 PUSHBUTTON "",IDC_ADVANCED,63,148,14,10,BS_TOP | BS_FLAT - GROUPBOX "Advanced Options",IDC_ADVANCED_GROUP,7,210,192,54,NOT WS_VISIBLE - COMBOBOX IDC_DISK_ID,119,246,73,30,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Advanced Options",IDS_ADVANCED_OPTIONS_GRP,7,210,192,54 + COMBOBOX IDC_DISK_ID,119,246,73,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Add fixes for old BIOSes (extra partition, align, etc.)",IDC_EXTRA_PARTITION, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,235,184,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,235,181,10 CONTROL "List fixed (non-flash) or unpartitioned USB disks",IDC_ENABLE_FIXED_DISKS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,222,185,10 - PUSHBUTTON "Log",IDC_LOG,62,291,18,14 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,222,181,10 END IDD_ABOUTBOX DIALOGEX 0, 0, 287, 201 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About Rufus" -FONT 8, "Microsoft Sans Serif", 400, 0, 0x0 +FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN ICON IDI_ICON,IDC_ABOUT_ICON,11,8,20,20 DEFPUSHBUTTON "OK",IDOK,231,181,50,14,WS_GROUP @@ -128,36 +128,35 @@ END IDD_UPDATE_POLICY DIALOGEX 0, 0, 287, 198 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Update policy and settings" -FONT 8, "Microsoft Sans Serif", 400, 0, 0x0 +FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN - ICON IDI_ICON,IDC_ABOUT_ICON,11,8,21,20 + ICON IDI_ICON,IDC_ABOUT_ICON,11,8,20,20 DEFPUSHBUTTON "Close",IDCANCEL,221,172,50,14,WS_GROUP CONTROL "",IDC_POLICY,"RichEdit20W",WS_VSCROLL | 0x804,46,8,235,130,WS_EX_STATICEDGE COMBOBOX IDC_UPDATE_FREQUENCY,133,155,66,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Check for updates:",IDC_STATIC,52,157,72,11 - LTEXT "Include beta versions:",IDC_STATIC,52,173,93,11 + LTEXT "Check for updates:",IDS_UPDATE_FREQUENCY_TXT,52,157,80,11 + LTEXT "Include beta versions:",IDS_INCLUDE_BETAS_TXT,52,173,80,11 COMBOBOX IDC_INCLUDE_BETAS,133,171,36,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Settings",IDC_STATIC,45,145,161,46 + GROUPBOX "Settings",IDS_UPDATE_SETTINGS_GRP,45,145,161,46 PUSHBUTTON "Check Now",IDC_CHECK_NOW,221,154,50,14 - GROUPBOX "",IDC_STATIC,210,145,71,46 + GROUPBOX "",IDS_CHECK_NOW_GRP,210,145,71,46 END IDD_NEW_VERSION DIALOGEX 0, 0, 384, 268 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Check For Updates - Rufus" -FONT 8, "Microsoft Sans Serif", 400, 0, 0x0 +FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN PUSHBUTTON "Close",IDCANCEL,167,244,50,14,WS_GROUP - CONTROL "",IDC_RELEASE_NOTES,"RichEdit20W",WS_VSCROLL | 0x804,15,77,352,88,WS_EX_STATICEDGE + CONTROL "",IDC_RELEASE_NOTES,"RichEdit20W",ES_MULTILINE | ES_READONLY | WS_VSCROLL,15,77,352,88,WS_EX_STATICEDGE DEFPUSHBUTTON "Download",IDC_DOWNLOAD,293,211,74,14,WS_GROUP CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,15,212,270,11 - GROUPBOX "Release Notes",IDC_STATIC,8,63,367,111 - LTEXT "A newer version is available. Please download the latest version!",IDC_STATIC,10,32,229,8 + GROUPBOX "Release Notes",IDS_NEW_VERSION_NOTES_GRP,8,63,367,111 + LTEXT "A newer version is available. Please download the latest version!",IDS_NEW_VERSION_AVAIL_TXT,10,32,229,8 LTEXT "[...]",IDC_YOUR_VERSION,10,8,124,8 LTEXT "[...]",IDC_LATEST_VERSION,10,19,129,8 - CONTROL "Click here to go to the website",IDC_WEBSITE, - "SysLink",WS_TABSTOP,143,49,96,9 - GROUPBOX "Download",IDC_STATIC,8,177,367,58 + LTEXT " Click here to go to the website",IDC_WEBSITE,138,49,108,9,SS_NOTIFY + GROUPBOX "Download",IDS_NEW_VERSION_DOWNLOAD_GRP,8,177,367,58 EDITTEXT IDC_DOWNLOAD_URL,15,191,351,13,ES_AUTOHSCROLL | ES_READONLY END @@ -185,6 +184,7 @@ END 3 TEXTINCLUDE BEGIN "\r\n" + "IDR_LC_RUFUS_LOC RCDATA ""../res/localization/rufus.loc""\r\n" "IDR_SL_LDLINUX_V4_BSS RCDATA ""../res/syslinux/ldlinux_v4.bss""\r\n" "IDR_SL_LDLINUX_V4_SYS RCDATA ""../res/syslinux/ldlinux_v4.sys""\r\n" "IDR_SL_LDLINUX_V5_BSS RCDATA ""../res/syslinux/ldlinux_v5.bss""\r\n" @@ -278,8 +278,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,0,280 - PRODUCTVERSION 1,4,0,280 + FILEVERSION 1,4,0,281 + PRODUCTVERSION 1,4,0,281 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -296,13 +296,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.4.0.280" + VALUE "FileVersion", "1.4.0.281" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2013 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.4.0.280" + VALUE "ProductVersion", "1.4.0.281" END END BLOCK "VarFileInfo" @@ -333,6 +333,7 @@ IDI_DOWN ICON "../res/down.ico" // Generated from the TEXTINCLUDE 3 resource. // +IDR_LC_RUFUS_LOC RCDATA "../res/localization/rufus.loc" IDR_SL_LDLINUX_V4_BSS RCDATA "../res/syslinux/ldlinux_v4.bss" IDR_SL_LDLINUX_V4_SYS RCDATA "../res/syslinux/ldlinux_v4.sys" IDR_SL_LDLINUX_V5_BSS RCDATA "../res/syslinux/ldlinux_v5.bss" diff --git a/src/stdfn.c b/src/stdfn.c index 7b1f21a6..da666421 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -26,6 +26,8 @@ #include "msapi_utf8.h" #include "rufus.h" +#include "resource.h" +#include "localization.h" // Must be in the same order as enum WindowsVersion static const char* WindowsVersionName[WINDOWS_MAX] = { @@ -232,7 +234,7 @@ BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size) goto out; } - PrintStatus(0, TRUE, "%s '%s'", save?"Saved":"Opened", path); + PrintStatus(0, TRUE, save?lmprintf(MSG_216, path):lmprintf(MSG_215, path)); ret = TRUE; out: diff --git a/src/stdio.c b/src/stdio.c index bfc7bbef..2c32f3a4 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -31,6 +31,7 @@ #include "msapi_utf8.h" #include "rufus.h" #include "resource.h" +#include "localization.h" /* * Globals @@ -40,7 +41,8 @@ HWND hStatus; #ifdef RUFUS_DEBUG void _uprintf(const char *format, ...) { - char buf[4096], *p = buf; + static char buf[4096]; + char* p = buf; va_list args; int n; @@ -50,7 +52,7 @@ void _uprintf(const char *format, ...) p += (n < 0)?sizeof(buf)-3:n; - while((p>buf) && (isspace((unsigned char)p[-1]))) + while((p>buf) && (isspaceU(p[-1]))) *--p = '\0'; *p++ = '\r'; @@ -145,23 +147,11 @@ static void CALLBACK PrintStatusTimeout(HWND hwnd, UINT uMsg, UINT_PTR idEvent, KillTimer(hMainDialog, TID_MESSAGE); } -void PrintStatus(unsigned int duration, BOOL debug, const char *format, ...) +void PrintStatus(unsigned int duration, BOOL debug, const char* message) { - char *p = szStatusMessage; - va_list args; - int n; - - va_start(args, format); - n = safe_vsnprintf(p, sizeof(szStatusMessage)-1, format, args); // room for NUL - va_end(args); - - p += (n < 0)?sizeof(szStatusMessage)-1:n; - - while((p>szStatusMessage) && (isspace(p[-1]))) - *--p = '\0'; - - *p = '\0'; - + if (message == NULL) + return; + safe_strcpy(szStatusMessage, sizeof(szStatusMessage), message); if (debug) uprintf("%s\n", szStatusMessage); @@ -192,17 +182,16 @@ char* GuidToString(const GUID* guid) char* SizeToHumanReadable(LARGE_INTEGER size) { int suffix = 0; - static char str_size[24]; - const char* sizes[] = { "", "KB", "MB", "GB", "TB" }; + static char str_size[32]; double hr_size = (double)size.QuadPart; - while ((suffix < ARRAYSIZE(sizes)) && (hr_size >= 1024.0)) { + while ((suffix < MAX_SIZE_SUFFIXES) && (hr_size >= 1024.0)) { hr_size /= 1024.0; suffix++; } if (suffix == 0) { - safe_sprintf(str_size, sizeof(str_size), "%d bytes", (int)hr_size); + safe_sprintf(str_size, sizeof(str_size), "%d %s", (int)hr_size, lmprintf(MSG_020)); } else { - safe_sprintf(str_size, sizeof(str_size), "%0.1f %s", hr_size, sizes[suffix]); + safe_sprintf(str_size, sizeof(str_size), "%0.1f %s", hr_size, lmprintf(MSG_020 + suffix)); } return str_size; } @@ -210,7 +199,7 @@ char* SizeToHumanReadable(LARGE_INTEGER size) const char* StrError(DWORD error_code) { if ( (!IS_ERROR(error_code)) || (SCODE_CODE(error_code) == ERROR_SUCCESS)) { - return "Success"; + return lmprintf(MSG_044); } if (SCODE_FACILITY(error_code) != FACILITY_STORAGE) { uprintf("StrError: non storage - %08X (%X)\n", error_code, SCODE_FACILITY(error_code)); @@ -219,63 +208,61 @@ const char* StrError(DWORD error_code) } switch (SCODE_CODE(error_code)) { case ERROR_GEN_FAILURE: - return "Undetermined error while formatting."; + return lmprintf(MSG_051); case ERROR_INCOMPATIBLE_FS: - return "Cannot use the selected file system for this media."; + return lmprintf(MSG_052); case ERROR_ACCESS_DENIED: - return "Access to the device is denied."; + return lmprintf(MSG_053); case ERROR_WRITE_PROTECT: - return "Media is write protected."; + return lmprintf(MSG_054); case ERROR_DEVICE_IN_USE: - return "The device is in use by another process. " - "Please close any other process that may be accessing the device."; + return lmprintf(MSG_055); case ERROR_CANT_QUICK_FORMAT: - return "Quick format is not available for this device."; + return lmprintf(MSG_056); case ERROR_LABEL_TOO_LONG: - return "The volume label is invalid."; + return lmprintf(MSG_057); case ERROR_INVALID_HANDLE: - return "The device handle is invalid."; + return lmprintf(MSG_058); case ERROR_INVALID_CLUSTER_SIZE: - return "The selected cluster size is not valid for this device."; + return lmprintf(MSG_059); case ERROR_INVALID_VOLUME_SIZE: - return "The volume size is invalid."; + return lmprintf(MSG_060); case ERROR_NO_MEDIA_IN_DRIVE: - return "Please insert a media in drive."; + return lmprintf(MSG_061); case ERROR_NOT_SUPPORTED: - return "An unsupported command was received."; + return lmprintf(MSG_062); case ERROR_NOT_ENOUGH_MEMORY: - return "Memory allocation error."; + return lmprintf(MSG_063); case ERROR_READ_FAULT: - return "Read error."; + return lmprintf(MSG_064); case ERROR_WRITE_FAULT: - return "Write error."; + return lmprintf(MSG_065); case ERROR_INSTALL_FAILURE: - return "Installation failure"; + return lmprintf(MSG_066); case ERROR_OPEN_FAILED: - return "Could not open media. It may be in use by another process. " - "Please re-plug the media and try again."; + return lmprintf(MSG_067); case ERROR_PARTITION_FAILURE: - return "Error while partitioning drive."; + return lmprintf(MSG_068); case ERROR_CANNOT_COPY: - return "Could not copy files to target drive."; + return lmprintf(MSG_069); case ERROR_CANCELLED: - return "Cancelled by user."; + return lmprintf(MSG_070); case ERROR_CANT_START_THREAD: - return "Unable to create formatting thread."; + return lmprintf(MSG_071); case ERROR_BADBLOCKS_FAILURE: - return "Bad blocks check didn't complete."; + return lmprintf(MSG_072); case ERROR_ISO_SCAN: - return "ISO image scan failure."; + return lmprintf(MSG_073); case ERROR_ISO_EXTRACT: - return "ISO image extraction failure."; + return lmprintf(MSG_074); case ERROR_CANT_REMOUNT_VOLUME: - return "Unable to remount volume."; + return lmprintf(MSG_075); case ERROR_CANT_PATCH: - return "Unable to patch/setup files for boot."; + return lmprintf(MSG_076); case ERROR_CANT_ASSIGN_LETTER: - return "Unable to assign a drive letter."; + return lmprintf(MSG_077); case ERROR_CANT_MOUNT_VOLUME: - return "Can't mount GUID volume."; + return lmprintf(MSG_078); default: uprintf("Unknown error: %08X\n", error_code); SetLastError(error_code); diff --git a/src/stdlg.c b/src/stdlg.c index 08fb6118..7189afb0 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -39,6 +39,7 @@ #include "registry.h" #include "resource.h" #include "license.h" +#include "localization.h" /* The following is only available on Vista and later */ #if (_WIN32_WINNT >= 0x0600) @@ -66,6 +67,7 @@ static const SETTEXTEX friggin_microsoft_unicode_amateurs = {ST_DEFAULT, CP_UTF8 static BOOL notification_is_question; static const notification_info* notification_more_info; static BOOL reg_commcheck = FALSE; +static WNDPROC original_wndproc = NULL; /* * We need a sub-callback to read the content of the edit box on exit and update @@ -222,7 +224,7 @@ fallback: INIT_XP_SHELL32; memset(&bi, 0, sizeof(BROWSEINFOW)); bi.hwndOwner = hMainDialog; - bi.lpszTitle = L"Please select the installation folder:"; + bi.lpszTitle = utf8_to_wchar(lmprintf(MSG_106)); bi.lpfn = BrowseInfoCallback; // BIF_NONEWFOLDERBUTTON = 0x00000200 is unknown on MinGW bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS | @@ -231,6 +233,7 @@ fallback: if (pidl != NULL) { CoTaskMemFree(pidl); } + safe_free(bi.lpszTitle); dialog_showing--; } @@ -244,7 +247,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des DWORD tmp; OPENFILENAMEA ofn; char selected_name[MAX_PATH]; - char* ext_string = NULL; + char *ext_string = NULL, *all_files = NULL; size_t i, ext_strlen; BOOL r; char* filepath = NULL; @@ -259,6 +262,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des IShellItem *si_path = NULL; // Automatically freed dialog_showing++; + memset(filter_spec, 0, sizeof(filter_spec)); INIT_VISTA_SHELL32; if (IS_VISTA_SHELL32_AVAILABLE) { // Setup the file extension filter table @@ -269,7 +273,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des safe_free(ext_filter); filter_spec[0].pszName = utf8_to_wchar(ext_desc); filter_spec[1].pszSpec = L"*.*"; - filter_spec[1].pszName = L"All files"; + filter_spec[1].pszName = utf8_to_wchar(lmprintf(MSG_107)); } hr = CoCreateInstance(save?&CLSID_FileSaveDialog:&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, @@ -305,6 +309,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des safe_free(wfilename); safe_free(filter_spec[0].pszSpec); safe_free(filter_spec[0].pszName); + safe_free(filter_spec[1].pszName); if (SUCCEEDED(hr)) { // Obtain the result of the user's interaction with the dialog. @@ -343,11 +348,12 @@ fallback: ofn.lpstrFile = selected_name; ofn.nMaxFile = MAX_PATH; // Set the file extension filters - ext_strlen = safe_strlen(ext_desc) + 2*safe_strlen(ext) + sizeof(" (*.)\0*.\0All Files (*.*)\0*.*\0\0"); + all_files = lmprintf(MSG_107); + ext_strlen = safe_strlen(ext_desc) + 2*safe_strlen(ext) + sizeof(" (*.)\0*.\0 (*.*)\0*.*\0\0") + safe_strlen(all_files); ext_string = (char*)malloc(ext_strlen); if (ext_string == NULL) return NULL; - safe_sprintf(ext_string, ext_strlen, "%s (*.%s)\r*.%s\rAll Files (*.*)\r*.*\r\0", ext_desc, ext, ext); + safe_sprintf(ext_string, ext_strlen, "%s (*.%s)\r*.%s\r%s (*.*)\r*.*\r\0", ext_desc, ext, ext, all_files); // Microsoft could really have picked a better delimiter! for (i=0; iid), + DialogBoxW(hMainInstance, MAKEINTRESOURCEW(notification_more_info->id), hDlg, notification_more_info->callback); break; } @@ -937,17 +987,19 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l HWND hPolicy; static HWND hFrequency, hBeta; int32_t freq; + char update_policy_text[4096]; switch (message) { case WM_INITDIALOG: + apply_localization(IDD_UPDATE_POLICY, hDlg); SetTitleBarIcon(hDlg); CenterDialog(hDlg); hFrequency = GetDlgItem(hDlg, IDC_UPDATE_FREQUENCY); hBeta = GetDlgItem(hDlg, IDC_INCLUDE_BETAS); - IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Disabled"), -1)); - IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Daily (Default)"), 86400)); - IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Weekly"), 604800)); - IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Monthly"), 2629800)); + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_013)), -1)); + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_030, lmprintf(MSG_014))), 86400)); + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_015)), 604800)); + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_016)), 2629800)); freq = ReadRegistryKey32(REGKEY_HKCU, REGKEY_UPDATE_INTERVAL); EnableWindow(GetDlgItem(hDlg, IDC_CHECK_NOW), (freq != 0)); EnableWindow(hBeta, (freq >= 0)); @@ -966,16 +1018,19 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 3)); break; default: - IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Custom"), freq)); + IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_017)), freq)); IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 4)); break; } - IGNORE_RETVAL(ComboBox_AddStringU(hBeta, "Yes")); - IGNORE_RETVAL(ComboBox_AddStringU(hBeta, "No")); + IGNORE_RETVAL(ComboBox_AddStringU(hBeta, lmprintf(MSG_008))); + IGNORE_RETVAL(ComboBox_AddStringU(hBeta, lmprintf(MSG_009))); IGNORE_RETVAL(ComboBox_SetCurSel(hBeta, GetRegistryKeyBool(REGKEY_HKCU, REGKEY_INCLUDE_BETAS)?0:1)); hPolicy = GetDlgItem(hDlg, IDC_POLICY); SendMessage(hPolicy, EM_AUTOURLDETECT, 1, 0); - SendMessageA(hPolicy, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update_policy); + safe_sprintf(update_policy_text, sizeof(update_policy_text), update_policy, lmprintf(MSG_179), + lmprintf(MSG_180), lmprintf(MSG_181), lmprintf(MSG_182), lmprintf(MSG_183), lmprintf(MSG_184), + lmprintf(MSG_185), lmprintf(MSG_186)); + SendMessageA(hPolicy, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update_policy_text); SendMessage(hPolicy, EM_SETSEL, -1, -1); SendMessage(hPolicy, EM_SETEVENTMASK, 0, ENM_LINK); SendMessageA(hPolicy, EM_SETBKGNDCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); @@ -984,6 +1039,7 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l switch (LOWORD(wParam)) { case IDCLOSE: case IDCANCEL: + reset_localization(IDD_UPDATE_POLICY); EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; case IDC_CHECK_NOW: @@ -1036,8 +1092,7 @@ BOOL SetUpdateCheck(void) uprintf("Short name used - Disabling initial update policy prompt\n"); enable_updates = TRUE; } else { - enable_updates = Notification(MSG_QUESTION, &more_info, APPLICATION_NAME " update policy", - "Do you want to allow " APPLICATION_NAME " to check for application updates?\n"); + enable_updates = Notification(MSG_QUESTION, &more_info, lmprintf(MSG_004), lmprintf(MSG_005)); } if (!enable_updates) { WriteRegistryKey32(REGKEY_HKCU, REGKEY_UPDATE_INTERVAL, -1); @@ -1051,6 +1106,48 @@ BOOL SetUpdateCheck(void) return TRUE; } +static void CreateStaticFont(HDC dc, HFONT* hyperlink_font) { + TEXTMETRIC tm; + LOGFONT lf; + + if (*hyperlink_font != NULL) + return; + GetTextMetrics(dc, &tm); + lf.lfHeight = tm.tmHeight; + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = tm.tmWeight; + lf.lfItalic = tm.tmItalic; + lf.lfUnderline = TRUE; + lf.lfStrikeOut = tm.tmStruckOut; + lf.lfCharSet = tm.tmCharSet; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = tm.tmPitchAndFamily; + GetTextFace(dc, LF_FACESIZE, lf.lfFaceName); + *hyperlink_font = CreateFontIndirect(&lf); +} + +/* + * Work around the limitations of edit control, to display a hand cursor for hyperlinks + * NB: The LTEXT control must have SS_NOTIFY attribute for this to work + */ +INT_PTR CALLBACK subclass_callback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_SETCURSOR: + if ((HWND)wParam == GetDlgItem(hDlg, IDC_WEBSITE)) { + SetCursor(LoadCursor(NULL, IDC_HAND)); + return (INT_PTR)TRUE; + } + break; + } + return CallWindowProc(original_wndproc, hDlg, message, wParam, lParam); +} + /* * New version notification dialog */ @@ -1058,64 +1155,55 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR { int i; HWND hNotes; - TEXTRANGEW tr; - ENLINK* enl; - wchar_t wUrl[256]; char tmp[128]; static char* filepath = NULL; static int download_status = 0; STARTUPINFOA si; PROCESS_INFORMATION pi; + HFONT hyperlink_font = NULL; switch (message) { case WM_INITDIALOG: + apply_localization(IDD_NEW_VERSION, hDlg); download_status = 0; SetTitleBarIcon(hDlg); CenterDialog(hDlg); + // Subclass the callback so that we can change the cursor + original_wndproc = (WNDPROC)SetWindowLongPtr(hDlg, GWLP_WNDPROC, (LONG_PTR)subclass_callback); hNotes = GetDlgItem(hDlg, IDC_RELEASE_NOTES); SendMessage(hNotes, EM_AUTOURLDETECT, 1, 0); SendMessageA(hNotes, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update.release_notes); SendMessage(hNotes, EM_SETSEL, -1, -1); SendMessage(hNotes, EM_SETEVENTMASK, 0, ENM_LINK); - safe_sprintf(tmp, sizeof(tmp), "Your version: %d.%d.%d (Build %d)", - rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]); - SetWindowTextA(GetDlgItem(hDlg, IDC_YOUR_VERSION), tmp); - safe_sprintf(tmp, sizeof(tmp), "Latest version: %d.%d.%d (Build %d)", - update.version[0], update.version[1], update.version[2], update.version[3]); - SetWindowTextA(GetDlgItem(hDlg, IDC_LATEST_VERSION), tmp); - SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD_URL), update.download_url); + SetWindowTextU(GetDlgItem(hDlg, IDC_YOUR_VERSION), lmprintf(MSG_018, + rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3])); + SetWindowTextU(GetDlgItem(hDlg, IDC_LATEST_VERSION), lmprintf(MSG_019, + update.version[0], update.version[1], update.version[2], update.version[3])); + SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD_URL), update.download_url); SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000); if (update.download_url == NULL) EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE); break; - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case NM_CLICK: - case NM_RETURN: - if (LOWORD(wParam) == IDC_WEBSITE) { - ShellExecuteA(hDlg, "open", RUFUS_URL, NULL, NULL, SW_SHOWNORMAL); - } - break; - case EN_LINK: - enl = (ENLINK*) lParam; - if (enl->msg == WM_LBUTTONUP) { - tr.lpstrText = wUrl; - tr.chrg.cpMin = enl->chrg.cpMin; - tr.chrg.cpMax = enl->chrg.cpMax; - SendMessageW(enl->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr); - wUrl[ARRAYSIZE(wUrl)-1] = 0; - ShellExecuteW(hDlg, L"open", wUrl, NULL, NULL, SW_SHOWNORMAL); - } - break; - } - break; + case WM_CTLCOLORSTATIC: + if ((HWND)lParam != GetDlgItem(hDlg, IDC_WEBSITE)) + return FALSE; + // Change the font for the hyperlink + SetBkMode((HDC)wParam, TRANSPARENT); + CreateStaticFont((HDC)wParam, &hyperlink_font); + SelectObject((HDC)wParam, hyperlink_font); + SetTextColor((HDC)wParam, RGB(0,0,125)); // DARK_BLUE + return (INT_PTR)CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); case WM_COMMAND: switch (LOWORD(wParam)) { case IDCLOSE: case IDCANCEL: + reset_localization(IDD_NEW_VERSION); safe_free(filepath); EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; + case IDC_WEBSITE: + ShellExecuteA(hDlg, "open", RUFUS_URL, NULL, NULL, SW_SHOWNORMAL); + break; case IDC_DOWNLOAD: // Also doubles as abort and launch function switch(download_status) { case 1: // Abort @@ -1130,17 +1218,17 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); if (!CreateProcessU(NULL, tmp, NULL, NULL, FALSE, 0, NULL, filepath, &si, &pi)) { - PrintStatus(0, FALSE, "Failed to launch new application"); + PrintStatus(0, FALSE, lmprintf(MSG_214)); uprintf("Failed to launch new application: %s\n", WindowsErrorString()); } else { - PrintStatus(0, FALSE, "Launching new application..."); + PrintStatus(0, FALSE, lmprintf(MSG_213)); PostMessage(hDlg, WM_COMMAND, (WPARAM)IDCLOSE, 0); PostMessage(hMainDialog, WM_CLOSE, 0, 0); } break; default: // Download for (i=(int)safe_strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--); - filepath = FileDialog(TRUE, app_dir, (char*)&update.download_url[i+1], "exe", "Application"); + filepath = FileDialog(TRUE, app_dir, (char*)&update.download_url[i+1], "exe", lmprintf(MSG_037)); if (filepath != NULL) DownloadFileThreaded(update.download_url, filepath, hDlg); break; @@ -1151,14 +1239,14 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR case UM_ISO_INIT: FormatStatus = 0; download_status = 1; - SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Abort"); + SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_038)); return (INT_PTR)TRUE; case UM_ISO_EXIT: if (wParam) { - SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Launch"); + SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_039)); download_status = 2; } else { - SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Download"); + SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_040)); download_status = 0; } return (INT_PTR)TRUE; @@ -1168,7 +1256,7 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR void DownloadNewVersion(void) { - DialogBoxA(hMainInstance, MAKEINTRESOURCEA(IDD_NEW_VERSION), hMainDialog, NewVersionCallback); + DialogBoxW(hMainInstance, MAKEINTRESOURCEW(IDD_NEW_VERSION), hMainDialog, NewVersionCallback); } void SetTitleBarIcon(HWND hDlg) diff --git a/src/syslinux.c b/src/syslinux.c index f01f7984..b3b70cf7 100644 --- a/src/syslinux.c +++ b/src/syslinux.c @@ -28,6 +28,7 @@ #include "rufus.h" #include "resource.h" +#include "localization.h" #include "syslinux.h" #include "syslxfs.h" @@ -91,7 +92,7 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter) int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); BOOL use_v5 = (dt == DT_SYSLINUX_V5) || ((dt == DT_ISO) && (iso_report.has_syslinux_v5)); - PrintStatus(0, TRUE, "Installing Syslinux v%d...", use_v5?5:4); + PrintStatus(0, TRUE, lmprintf(MSG_234, use_v5?5:4)); ldlinux_path[0] = drive_letter;