mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[pollock] add automatic PO generation and update detection
* Also use Rufus application version in .loc
This commit is contained in:
		
							parent
							
								
									af9cca5fb3
								
							
						
					
					
						commit
						d9d0feadb6
					
				
					 5 changed files with 563 additions and 213 deletions
				
			
		|  | @ -15,13 +15,13 @@ content. PLEASE, do not just look at this Changelog when updating your | |||
| translation, but always use the English section of rufus.loc as your base. | ||||
| For instance, MSG_114, that was introduced in v1.0.8 is MORE than one line! | ||||
| 
 | ||||
| o Version 1.0.24 (2018.??.??) | ||||
| o v3.2 (2018.??.??) | ||||
|   - *NEW*      MSG_087 | ||||
|   - *NEW*      MSG_172 | ||||
|   - *NEW*      MSG_199 | ||||
|   - *NEW*      MSG_306 | ||||
| 
 | ||||
| o Version 1.0.23 (2018.03.27) | ||||
| o v3.0 (2018.03.27) | ||||
|   - All positioning ('m', 's') has now been removed as well as some controls, for the 3.0 UI redesign | ||||
|   - *NEW*      IDS_DRIVE_PROPERTIES_TXT "Drive Properties" | ||||
|   - *NEW*      IDS_BOOT_SELECTION_TXT "Boot selection" | ||||
|  | @ -73,7 +73,7 @@ o Version 1.0.23 (2018.03.27) | |||
|                for the languages who did that. This means that "Save Log", "Clear Log" "Close Log" have become "Save", "Clear", "Close". | ||||
|                *PLEASE* verify that the modification looks correct in your language. | ||||
| 
 | ||||
| o Version 1.0.22 (2017.07.17) | ||||
| o v2.16 (2017.07.17) | ||||
|   - *NEW* MSG_295 "Warning: Unofficial version" | ||||
|   - *NEW* MSG_296 "This version of Rufus was NOT produced by its official developer(s).\n\nAre you sure you want to run it?" | ||||
|   - *NEW* MSG_297 "Truncated ISO detected" | ||||
|  | @ -82,7 +82,7 @@ o Version 1.0.22 (2017.07.17) | |||
|     "official ones.\n\nNote that you can compute the MD5 or SHA in Rufus by clicking the '#' button." | ||||
|   Note: You can test MSG_297/MSG_298 using https://rufus.akeo.ie/testing/arch_trunc.iso (A truncated version of archlinux-2017.07.01-x86_64.iso) | ||||
| 
 | ||||
| o Version 1.0.21 (2017.01.16) | ||||
| o v2.12 (2017.01.16) | ||||
|   - *NEW* MSG_288 "Missing elevated privileges" | ||||
|   - *NEW* MSG_289 "This application can only run with elevated privileges" | ||||
|     This message, along with the previous, is just to notify the user when they have | ||||
|  | @ -104,7 +104,7 @@ o Version 1.0.21 (2017.01.16) | |||
|   - *NEW* MSG_294 "This version of Windows is no longer supported by Rufus." | ||||
|     These two messages are not used anywhere yet, but may be needed in a future prompt. | ||||
| 
 | ||||
| o Version 1.0.20 (2016.05.09) | ||||
| o v2.9 (2016.05.09) | ||||
|   - *NEW* MSG_286 "Zeroing drive: %0.1f%% completed" | ||||
|     Used when filling a whole drive with zero bytes, to display progress in percent (e.g. "Zeroing drive: 12.3% completed") | ||||
|     Can be tested with Alt-Z (CAUTION: THIS WILL COMPLETELY ERASE THE SELECTED DRIVE!!) | ||||
|  | @ -112,7 +112,7 @@ o Version 1.0.20 (2016.05.09) | |||
|     Note, this message is followed by either "enabled"/"disabled" (see MSG_250/251) and is similar to MSG_253 | ||||
|     The message appears on the status bar and can be tested with Ctrl-Alt-F. | ||||
| 
 | ||||
| o Version 1.0.19 (2015.10.15) | ||||
| o v2.5 (2015.10.15) | ||||
|     Note: The following message can be tested by pressing Alt-, (That's the 'Alt' and 'comma' keys on your keyboard) | ||||
|           In case the message below is not clear, you can consider that it says "Exclusive locking of the USB drive" | ||||
|   - *NEW* MSG_282 "Exclusive USB drive locking" | ||||
|  | @ -123,7 +123,7 @@ o Version 1.0.19 (2015.10.15) | |||
|   - *NEW* MSG_285 "The downloaded executable is signed by '%s'.\nThis is not a signature we recognize and could " | ||||
|                   "indicate some form of malicious activity...\nAre you sure you want to run this file?" | ||||
| 
 | ||||
| o Version 1.0.18 (2015.09.03) | ||||
| o v2.4 (2015.09.03) | ||||
|   - Changed MSG_081 "Unsupported ISO" -> "Unsupported image" | ||||
|   - Changed MSG_082 -> "This image is either non-bootable, or it uses a boot or compression method that is not supported by Rufus..." | ||||
|   - *NEW* MSG_269 "Preserve timestamps" | ||||
|  | @ -148,7 +148,7 @@ o Version 1.0.18 (2015.09.03) | |||
|   - *NEW* MSG_280 "Image selection" | ||||
|   - *NEW* MSG_281 "(Please select an image)" | ||||
| 
 | ||||
| o Version 1.0.17 (2015.02.04) | ||||
| o v2.0 (2015.02.04) | ||||
|   - *NEW CONTROL* IDC_WINDOWS_INSTALL "Standard Windows installation" (Main dialog) | ||||
|   - *NEW CONTROL* IDC_WINDOWS_TO_GO "Windows To Go" (Main dialog) | ||||
|   Note: to see the 2 controls above displayed, you will need to load the "Windows To Go.iso" image from | ||||
|  |  | |||
|  | @ -20,9 +20,12 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Net; | ||||
| using System.Net.Cache; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Text.RegularExpressions; | ||||
|  | @ -58,6 +61,25 @@ namespace pollock | |||
|             this.group = group; | ||||
|             this.id = id; | ||||
|         } | ||||
| 
 | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             Id o = obj as Id; | ||||
| 
 | ||||
|             return (o.group == this.group) && (o.id == this.id); | ||||
|         } | ||||
| 
 | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return (this.group + ":" + this.id).GetHashCode(); | ||||
|         } | ||||
| 
 | ||||
|         public override string ToString() | ||||
|         { | ||||
|             if (this.group == "MSG") | ||||
|                 return this.id; | ||||
|             return this.group + " → " + this.id; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public sealed class Language | ||||
|  | @ -67,20 +89,23 @@ namespace pollock | |||
|         public string version; | ||||
|         public string lcid; | ||||
|         public SortedDictionary<string, List<Message>> sections; | ||||
|         public Dictionary<string, string> comments; | ||||
|         public Dictionary<Id, string> comments; | ||||
|         public Dictionary<Id, string> id_to_str; | ||||
|         public Language() | ||||
|         { | ||||
|             sections = new SortedDictionary<string, List<Message>>(); | ||||
|             comments = new Dictionary<string, string>(); | ||||
|             comments = new Dictionary<Id, string>(); | ||||
|             id_to_str = new Dictionary<Id, string>(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     class Pollock | ||||
|     { | ||||
|         private static string app_name = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; | ||||
|         private static string app_version = "v" | ||||
|             + Assembly.GetEntryAssembly().GetName().Version.Major.ToString() + "." | ||||
|             + Assembly.GetEntryAssembly().GetName().Version.Minor.ToString(); | ||||
|         private static string app_name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Assembly.GetExecutingAssembly().GetName().Name); | ||||
|         private static int[] version = new int[2] | ||||
|             { Assembly.GetEntryAssembly().GetName().Version.Major, Assembly.GetEntryAssembly().GetName().Version.Minor }; | ||||
|         private static string version_str = "v" + version[0].ToString() + "." + version[1].ToString(); | ||||
|         private static string app_path = AppDomain.CurrentDomain.BaseDirectory; | ||||
|         private static bool cancel_requested = false; | ||||
|         private const string LANG_ID = "Language"; | ||||
|         private const string LANG_NAME = "X-Rufus-LanguageName"; | ||||
|  | @ -88,35 +113,41 @@ namespace pollock | |||
|         private const string LANG_LCID = "X-Rufus-LCID"; | ||||
|         private static Encoding encoding = new UTF8Encoding(false); | ||||
|         private static List<string> rtl_languages = new List<string> { "ar-SA", "he-IL", "fa-IR" }; | ||||
|         private static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); | ||||
|         private static Stopwatch sw = new System.Diagnostics.Stopwatch(); | ||||
|         private static WebClient wc = new WebClient(); | ||||
|         private static DateTime last_changed = DateTime.MinValue; | ||||
|         private static int download_status; | ||||
|         private static int console_x_pos; | ||||
|         private static bool in_progress = false; | ||||
|         private static bool in_on_change = false; | ||||
|         private static double speed = 0.0f; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Wait for a key to be pressed. | ||||
|         /// </summary> | ||||
|         static void WaitForKey() | ||||
|         static void WaitForKey(string msg = null) | ||||
|         { | ||||
|             if (msg == null) | ||||
|                 msg = "Press any key to continue..."; | ||||
|             // Flush the input buffer | ||||
|             while (Console.KeyAvailable) | ||||
|                 Console.ReadKey(true); | ||||
|             Console.WriteLine(""); | ||||
|             Console.WriteLine("Press any key to exit..."); | ||||
|             Console.WriteLine(msg); | ||||
|             Console.ReadKey(true); | ||||
|             while (Console.KeyAvailable) | ||||
|                 Console.ReadKey(true); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Import languages from an existing rufus.loc | ||||
|         /// Import languages from an existing Rufus loc file | ||||
|         /// </summary> | ||||
|         /// <param name="path">The directy where the loc file is located.</param> | ||||
|         /// <param name="file">The name of the loc file.</param> | ||||
|         /// <param name="select_id">(Optional) If specified, only the language with this id, along with en-US will be returned.</param> | ||||
|         /// <returns>A list of Language elements.</returns> | ||||
|         static List<Language> ParseLocFile(string path, string id = null) | ||||
|         static List<Language> ParseLocFile(string file, string select_id = null) | ||||
|         { | ||||
|             var rufus_loc = path + @"\rufus.loc"; | ||||
|             var rufus_pot = path + @"\rufus.pot"; | ||||
|             var lines = File.ReadAllLines(rufus_loc); | ||||
|             var lines = File.ReadAllLines(file); | ||||
|             int line_nr = 0; | ||||
|             string format = "D" + (int)(Math.Log10((double)lines.Count()) + 0.99999); | ||||
|             string last_key = null; | ||||
|  | @ -126,24 +157,24 @@ namespace pollock | |||
|             List<Language> langs = new List<Language>(); | ||||
|             Language lang = null; | ||||
|             bool skip_line = false; | ||||
|             bool found_my_id = false; | ||||
|             Id id; | ||||
| 
 | ||||
|             sw.Start(); | ||||
| 
 | ||||
|             if (!File.Exists(rufus_loc)) | ||||
|             if (!File.Exists(file)) | ||||
|             { | ||||
|                 Console.Error.WriteLine($"Could not open {rufus_loc}"); | ||||
|                 Console.Error.WriteLine($"Could not open {file}"); | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             Console.WriteLine($"Importing data from '{rufus_loc}':"); | ||||
|             Console.Write($"Importing data from '{file}'... "); | ||||
| 
 | ||||
|             foreach (var line in lines) | ||||
|             { | ||||
|                 if (cancel_requested) | ||||
|                 if ((cancel_requested) || (found_my_id && skip_line)) | ||||
|                     break; | ||||
|                 ++line_nr; | ||||
|                 Console.SetCursorPosition(0, Console.CursorTop); | ||||
|                 Console.Write($"[{line_nr.ToString(format)}/{lines.Count()}] "); | ||||
|                 //Console.SetCursorPosition(0, Console.CursorTop); | ||||
|                 //Console.Write($"[{line_nr.ToString(format)}/{lines.Count()}] "); | ||||
|                 var data = line.Trim(); | ||||
|                 int i = data.IndexOf("#"); | ||||
|                 if (i > 0) | ||||
|  | @ -171,13 +202,17 @@ namespace pollock | |||
|                             Console.WriteLine("Error: Invalid 'l' command"); | ||||
|                             return null; | ||||
|                         } | ||||
|                         string lid = parts[1].Replace("\"", ""); | ||||
|                         if (id != null) | ||||
|                         string cur_id = parts[1].Replace("\"", ""); | ||||
|                         if (select_id != null) | ||||
|                         { | ||||
|                             if ((!skip_line) && (id != lid) && (lid != "en-US")) | ||||
|                             if ((select_id == "en-US") && (cur_id != "en-US")) | ||||
|                                 skip_line = true; | ||||
|                             else if (skip_line && (id == lid)) | ||||
|                             else if ((!skip_line) && (select_id != cur_id) && (cur_id != "en-US")) | ||||
|                                 skip_line = true; | ||||
|                             else if (skip_line && (select_id == cur_id)) | ||||
|                                 skip_line = false; | ||||
|                             if (select_id == cur_id) | ||||
|                                 found_my_id = true; | ||||
|                             if (skip_line) | ||||
|                                 break; | ||||
|                         } | ||||
|  | @ -186,7 +221,7 @@ namespace pollock | |||
|                         lang = new Language(); | ||||
|                         lang.id = parts[1].Replace("\"", ""); | ||||
|                         lang.name = parts[2].Replace("\"", ""); | ||||
|                         Console.WriteLine($"Found language {lang.id} '{lang.name}'"); | ||||
|                         //Console.WriteLine($"Found language {lang.id} '{lang.name}'"); | ||||
|                         lang.lcid = parts[3]; | ||||
|                         for (i = 4; i < parts.Count; i++) | ||||
|                             lang.lcid += " " + parts[i]; | ||||
|  | @ -223,10 +258,14 @@ namespace pollock | |||
|                             continue; | ||||
|                         } | ||||
|                         lang.sections[section_name].Add(new Message(parts[1], parts[2])); | ||||
|                         // We also maintain global list of Id -> str for convenience | ||||
|                         // TODO: This lookup BREAKS on multiline!! | ||||
|                         lang.id_to_str.Add(new Id(section_name, (parts[1])), parts[2]); | ||||
|                         last_key = parts[1]; | ||||
|                         if (comment != null) | ||||
|                         { | ||||
|                             lang.comments[last_key] = comment.Trim(); | ||||
|                             id = new Id(section_name, last_key); | ||||
|                             lang.comments[id] = comment.Trim(); | ||||
|                             comment = null; | ||||
|                         } | ||||
|                         break; | ||||
|  | @ -238,16 +277,16 @@ namespace pollock | |||
|                         } | ||||
|                         lang.sections[section_name].Last().str += data; | ||||
|                         lang.sections[section_name].Last().str = lang.sections[section_name].Last().str.Replace("\"\"", ""); | ||||
|                         id = new Id(section_name, last_key); | ||||
|                         lang.id_to_str[id] += data; | ||||
|                         lang.id_to_str[id] = lang.id_to_str[id].Replace("\"\"", ""); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|             if (lang != null) | ||||
|                 langs.Add(lang); | ||||
| 
 | ||||
|             sw.Stop(); | ||||
|             Console.WriteLine($"{(cancel_requested ? "CANCELLED after" : "DONE in")}" + | ||||
|                 $" {sw.ElapsedMilliseconds / 1000.0}s."); | ||||
|             sw.Reset(); | ||||
|             Console.WriteLine(cancel_requested ? "CANCELLED" : "DONE"); | ||||
| 
 | ||||
|             return langs; | ||||
|         } | ||||
|  | @ -255,37 +294,67 @@ namespace pollock | |||
|         /// <summary> | ||||
|         /// Create .po/.pot files from a list of Language elements. | ||||
|         /// </summary> | ||||
|         /// <param name="path">The path where the .po/.pot files should be created.</param> | ||||
|         /// <param name="langs">A lits of Languages elements</param> | ||||
|         /// <returns>true on success, false on error.</returns> | ||||
|         static bool CreatePoFiles(string path, List<Language> langs, bool merge_pot = false) | ||||
|         /// <param name="langs">A lits of Language objects to process.</param> | ||||
|         /// <param name="old_en_US">(Optional) A previous version of en-US to use for comparison.</param> | ||||
|         /// <param name="path">(Optional) The path where the .po/.pot files should be created.</param> | ||||
|         /// <returns>The number of PO files created.</returns> | ||||
|         static int CreatePoFiles(List<Language> langs, Language old_en_US = null, string path = null) | ||||
|         { | ||||
|             if (langs == null) | ||||
|                 return false; | ||||
|                 return 0; | ||||
| 
 | ||||
|             var en_US = langs.Find(x => x.id == "en-US"); | ||||
|             if (en_US == null) | ||||
|                 return false; | ||||
|             var cur_en_US = langs.Find(x => x.id == "en-US"); | ||||
|             if (cur_en_US == null) | ||||
|                 return 0; | ||||
| 
 | ||||
|             var msg_to_ids = new Dictionary<string, List<Id>>(); | ||||
|             if (path == null) | ||||
|                 path = app_path; | ||||
|             if (!path.EndsWith("\\")) | ||||
|                 path += '\\'; | ||||
| 
 | ||||
|             // Build a dictionary of message string to List<Id> so that we can identify duplicates and remove them | ||||
|             foreach (var section in en_US.sections) | ||||
|             // Build the list of all the current IDs we need to process | ||||
|             var en_ids = new List<Id>(); | ||||
|             foreach (var kvp in cur_en_US.id_to_str) | ||||
|                 en_ids.Add(new Id(kvp.Key.group, kvp.Key.id)); | ||||
| 
 | ||||
|             var added_ids = new List<Id>(); | ||||
|             var modified_ids = new List<Id>(); | ||||
| 
 | ||||
|             if (old_en_US != null) | ||||
|             { | ||||
|                 foreach (var msg in section.Value) | ||||
|                 foreach (var id in cur_en_US.id_to_str.Keys) | ||||
|                 { | ||||
|                     if (msg_to_ids.ContainsKey(msg.str)) | ||||
|                         msg_to_ids[msg.str].Add(new Id(section.Key, msg.id)); | ||||
|                     else | ||||
|                         msg_to_ids.Add(msg.str, new List<Id>() { new Id(section.Key, msg.id) }); | ||||
|                     if (!old_en_US.id_to_str.ContainsKey(id)) | ||||
|                     { | ||||
|                         // ID is not present in old -> added | ||||
|                         //Console.WriteLine($"ADDED: {id} = {cur_en_US.id_to_str[id]}"); | ||||
|                         added_ids.Add(id); | ||||
|                     } | ||||
|                     else if (old_en_US.id_to_str[id] != cur_en_US.id_to_str[id]) | ||||
|                     { | ||||
|                         // Ignore messages where we just removed the trailing \n | ||||
|                         if (!old_en_US.id_to_str[id].EndsWith("\\n\"")) | ||||
|                         { | ||||
|                             // ID exists in both but str has changed -> modified | ||||
|                             //Console.WriteLine($"MODIFIED: {id} = {old_en_US.id_to_str[id]} → {cur_en_US.id_to_str[id]}"); | ||||
|                             modified_ids.Add(id); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             int nb_po_saved = 0; | ||||
|             foreach (var lang in langs) | ||||
|             { | ||||
|                 bool is_pot = (lang.id == "en-US"); | ||||
|                 var target = path + @"\" + (is_pot ? "rufus.pot" : lang.id + ".po"); | ||||
|                 Console.WriteLine($"Creating '{target}'"); | ||||
|                 // Don't create the .pot if we are producing a merge | ||||
|                 if (is_pot && old_en_US != null) | ||||
|                     continue; | ||||
|                 var target = path + (is_pot ? "rufus.pot" : lang.id + ".po"); | ||||
|                 if (old_en_US != null) | ||||
|                     Console.Write($"Computing differences and creating '{target}'... "); | ||||
|                 else | ||||
|                     Console.Write($"Creating '{target}'... "); | ||||
| 
 | ||||
|                 using (var writer = new StreamWriter(target, false, encoding)) | ||||
|                 { | ||||
|  | @ -311,50 +380,59 @@ namespace pollock | |||
| 
 | ||||
|                     var dupes = new List<string>(); | ||||
| 
 | ||||
|                     foreach (var section in lang.sections) | ||||
|                     foreach(var id in en_ids) | ||||
|                     { | ||||
|                         foreach (var msg in section.Value) | ||||
|                         var en_str = cur_en_US.sections[id.group].Find(x => x.id == id.id).str; | ||||
|                         // Handle duplicate IDs | ||||
|                         if (dupes.Contains(en_str)) | ||||
|                             continue; | ||||
| 
 | ||||
|                         writer.WriteLine(); | ||||
| 
 | ||||
|                         var cid_list = cur_en_US.id_to_str.Where(x => x.Value == en_str).Select(x => x.Key); | ||||
|                         foreach (var cid in cid_list) | ||||
|                             writer.WriteLine($"#. • {cid}"); | ||||
|                         if (cid_list.Count() > 1) | ||||
|                             dupes.Add(en_str); | ||||
| 
 | ||||
|                         if (cur_en_US.comments.ContainsKey(id)) | ||||
|                         { | ||||
|                             var en_str = en_US.sections[section.Key].Find(x => x.id == msg.id).str; | ||||
| 
 | ||||
|                             // Handle duplicates | ||||
|                             if (dupes.Contains(en_str)) | ||||
|                                 continue; | ||||
|                             writer.WriteLine(); | ||||
|                             foreach (var id in msg_to_ids[en_str]) | ||||
|                             { | ||||
|                                 if (id.group == "MSG") | ||||
|                                     writer.WriteLine($"#. • {id.id}"); | ||||
|                                 else | ||||
|                                     writer.WriteLine($"#. • {id.group} → {id.id}"); | ||||
|                             } | ||||
|                             if (msg_to_ids[en_str].Count > 1) | ||||
|                                 dupes.Add(en_str); | ||||
| 
 | ||||
|                             if (lang.comments.ContainsKey(msg.id)) | ||||
|                             { | ||||
|                                 if (is_pot) | ||||
|                                     writer.WriteLine("#."); | ||||
|                                 foreach (var comment in lang.comments[msg.id].Split('\n')) | ||||
|                                     if (comment.Trim() != "") | ||||
|                                         writer.WriteLine((is_pot ? "#. " : "# ") + comment); | ||||
|                             } | ||||
|                             if (is_pot) | ||||
|                             { | ||||
|                                 writer.WriteLine($"msgid {msg.str}"); | ||||
|                                 writer.WriteLine("msgstr \"\""); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 writer.WriteLine($"msgid {en_str}"); | ||||
|                                 writer.WriteLine($"msgstr {msg.str}"); | ||||
|                             } | ||||
|                             writer.WriteLine("#."); | ||||
|                             foreach (var comment in cur_en_US.comments[id].Split('\n')) | ||||
|                                 if (comment.Trim() != "") | ||||
|                                     writer.WriteLine("#. " + comment); | ||||
|                         } | ||||
|                         if (!is_pot && lang.comments.ContainsKey(id)) | ||||
|                         { | ||||
|                             foreach (var comment in lang.comments[id].Split('\n')) | ||||
|                                 if (comment.Trim() != "") | ||||
|                                     writer.WriteLine("# " + comment); | ||||
|                         } | ||||
|                         // Flag the new/modified messages as requiring work | ||||
|                         if ((old_en_US != null) && (added_ids.Contains(id) || modified_ids.Contains(id))) | ||||
|                             writer.WriteLine("#, fuzzy"); | ||||
|                         string msg_str = lang.sections[id.group].Where(x => x.id == id.id).Select(x => x.str).FirstOrDefault(); | ||||
|                         // Special case for MSG_240, which we missed in the last round | ||||
|                         if (id.group == "MSG" && id.id == "MSG_240" && msg_str == null) | ||||
|                             writer.WriteLine("#, fuzzy"); | ||||
|                         if (msg_str == null) | ||||
|                             msg_str = "\"\""; | ||||
|                         if (is_pot) | ||||
|                         { | ||||
|                             writer.WriteLine($"msgid {msg_str}"); | ||||
|                             writer.WriteLine("msgstr \"\""); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             writer.WriteLine($"msgid {en_str}"); | ||||
|                             writer.WriteLine($"msgstr {msg_str}"); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 nb_po_saved++; | ||||
|             } | ||||
|             Console.WriteLine("DONE."); | ||||
|             return true; | ||||
|             Console.WriteLine("DONE"); | ||||
|             return nb_po_saved; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -476,9 +554,9 @@ namespace pollock | |||
|                         { | ||||
|                             if (comments != null) | ||||
|                             { | ||||
|                                 lang.comments.Add(id.id, ""); | ||||
|                                 lang.comments.Add(id, ""); | ||||
|                                 foreach (var comment in comments) | ||||
|                                     lang.comments[id.id] += comment + "\n"; | ||||
|                                     lang.comments[id] += comment + "\n"; | ||||
|                             } | ||||
|                             // Ignore messages that have the same translation as en-US | ||||
|                             if (msg_data[0] == msg_data[1]) | ||||
|  | @ -528,9 +606,10 @@ namespace pollock | |||
|                     writer.WriteLine($"g {section}"); | ||||
|                 foreach (var msg in lang.sections[section]) | ||||
|                 { | ||||
|                     if (lang.comments.ContainsKey(msg.id)) | ||||
|                     var id = new Id(section, msg.id); | ||||
|                     if (lang.comments.ContainsKey(id)) | ||||
|                     { | ||||
|                         foreach (var l in lang.comments[msg.id].Split('\n')) | ||||
|                         foreach (var l in lang.comments[id].Split('\n')) | ||||
|                             if (l.Trim() != "") | ||||
|                                 writer.WriteLine($"# {l}"); | ||||
|                     } | ||||
|  | @ -540,16 +619,21 @@ namespace pollock | |||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Create a new rufus.loc from a list of Language elements. | ||||
|         /// Update a rufus.loc section from a language element. | ||||
|         /// </summary> | ||||
|         /// <param name="path">The path where the new 'rufus.loc' should be created.</param> | ||||
|         /// <param name="list">The list of Language elements.</param> | ||||
|         /// <param name="lang">The Language elements to update.</param> | ||||
|         /// <param name="path">(Optional) The path where 'rufus.loc' is located.</param> | ||||
|         /// <returns>true on success, false on error.</returns> | ||||
|         static bool UpdateLocFile(string path, Language lang) | ||||
|         static bool UpdateLocFile(Language lang, string path = null) | ||||
|         { | ||||
|             if (lang == null) | ||||
|                 return false; | ||||
|             var target = path + @"\rufus.loc"; | ||||
|             if (path == null) | ||||
|                 path = app_path; | ||||
|             if (!path.EndsWith("\\")) | ||||
|                 path += '\\'; | ||||
| 
 | ||||
|             var target = path + "rufus.loc"; | ||||
|             var lines = File.ReadAllLines(target); | ||||
|             using (var writer = new StreamWriter(target, false, encoding)) | ||||
|             { | ||||
|  | @ -576,21 +660,25 @@ namespace pollock | |||
|         /// <summary> | ||||
|         /// Create a new rufus.loc from a list of Language elements. | ||||
|         /// </summary> | ||||
|         /// <param name="path">The path where the new 'rufus.loc' should be created.</param> | ||||
|         /// <param name="list">The list of Language elements.</param> | ||||
|         /// <param name="path">(Optional) The path where the new 'rufus.loc' should be created.</param> | ||||
|         /// <returns>true on success, false on error.</returns> | ||||
|         static bool SaveLocFile(string path, List<Language> list) | ||||
|         static bool SaveLocFile(List<Language> list, string path = null) | ||||
|         { | ||||
|             if ((list == null) || (list.Count == 0)) | ||||
|                 return false; | ||||
|             var target = path + @"\rufus.loc"; | ||||
|             if (path == null) | ||||
|                 path = app_path; | ||||
|             if (!path.EndsWith("\\")) | ||||
|                 path += '\\'; | ||||
|             var target = path + "rufus.loc"; | ||||
| 
 | ||||
|             sw.Start(); | ||||
| 
 | ||||
|             Console.WriteLine($"Creating '{target}':"); | ||||
|             using (var writer = new StreamWriter(target, false, encoding)) | ||||
|             { | ||||
|                 var notice = $"### Autogenerated by {app_name} {app_version} for use with Rufus - DO NOT EDIT!!! ###"; | ||||
|                 var notice = $"### Autogenerated by {app_name} {version_str} for use with Rufus - DO NOT EDIT!!! ###"; | ||||
|                 var sep = new String('#', notice.Length); | ||||
|                 writer.WriteLine(sep); | ||||
|                 writer.WriteLine(notice); | ||||
|  | @ -620,25 +708,102 @@ namespace pollock | |||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         static bool DownloadFile(string url, string dest) | ||||
|         /// <summary> | ||||
|         /// Validate a download URL by checking its HTTP status code. | ||||
|         /// </summary> | ||||
|         /// <param name="url">The URL to validate.</param> | ||||
|         /// <returns>true if URL is acessible, false on error.</returns> | ||||
|         static bool ValidateDownload(string url) | ||||
|         { | ||||
|             download_status = 0; | ||||
|             in_progress = false; | ||||
|             HttpStatusCode status = HttpStatusCode.NotFound; | ||||
|             var uri = new Uri(url); | ||||
|             WebRequest request = WebRequest.Create(uri); | ||||
|             request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); | ||||
|             request.Method = "HEAD"; | ||||
| 
 | ||||
|             // This is soooooooo retarded. Trying to simply read a 404 response throws a 404 *exception*?!? | ||||
|             try | ||||
|             { | ||||
|                 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | ||||
|                 status = response.StatusCode; | ||||
|             } | ||||
|             catch (WebException we) | ||||
|             { | ||||
|                 HttpWebResponse response = we.Response as HttpWebResponse; | ||||
|                 status = response.StatusCode; | ||||
|             } | ||||
|             switch (status) | ||||
|             { | ||||
|                 case HttpStatusCode.OK: | ||||
|                     return true; | ||||
|                 default: | ||||
|                     Console.WriteLine($"Error downloading {url}: {(int)status} - {status}"); | ||||
|                     return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Download a file as a string. Codepage is assumed to be UTF-8. | ||||
|         /// </summary> | ||||
|         /// <param name="url">The URL to download from.</param> | ||||
|         /// <returns>The downloaded string or null on error.</returns> | ||||
|         static string DownloadString(string url) | ||||
|         { | ||||
|             string str = null; | ||||
| 
 | ||||
|             if (!ValidateDownload(url)) | ||||
|                 return null; | ||||
| 
 | ||||
|             using (wc) | ||||
|             { | ||||
|                 wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted); | ||||
|                 wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress); | ||||
| 
 | ||||
|                 Console.WriteLine($"Downloading {url}:"); | ||||
|                 sw.Start(); | ||||
| 
 | ||||
|                 try | ||||
|                 { | ||||
|                     wc.DownloadFileAsync(new Uri(url), dest); | ||||
|                     str = System.Text.Encoding.UTF8.GetString(wc.DownloadData(new Uri(url))); | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.WriteLine("ERROR: " + e.Message); | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|             return str; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Download a file. | ||||
|         /// </summary> | ||||
|         /// <param name="url">The URL to download from.</param> | ||||
|         /// <param name="dest">(Optional) The destination file. | ||||
|         /// If not provided the file is saved in the current directory, using the last part of the URL as its name.</param> | ||||
|         /// <returns>true if the download was complete, false otherwise.</returns> | ||||
|         static bool DownloadFile(string url, string dest = null) | ||||
|         { | ||||
|             download_status = 0; | ||||
|             in_progress = false; | ||||
|             var uri = new Uri(url); | ||||
| 
 | ||||
|             if (dest == null) | ||||
|                 dest = url.Split('/').Last(); | ||||
| 
 | ||||
|             if (!ValidateDownload(url)) | ||||
|                 return false; | ||||
| 
 | ||||
|             console_x_pos = Console.CursorLeft; | ||||
|             using (wc) | ||||
|             { | ||||
|                 wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); | ||||
|                 wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted); | ||||
|                 wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress); | ||||
| 
 | ||||
|                 sw.Start(); | ||||
| 
 | ||||
|                 try | ||||
|                 { | ||||
|                     wc.DownloadFileAsync(uri, dest); | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.WriteLine(" Error: " + e.Message); | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|  | @ -647,16 +812,13 @@ namespace pollock | |||
| 
 | ||||
|             Console.WriteLine(); | ||||
|             if (download_status == 1) | ||||
|             { | ||||
|                 Console.WriteLine("Download complete"); | ||||
|                 return true; | ||||
|             } | ||||
|              | ||||
|             Console.WriteLine("Download has been canceled."); | ||||
| 
 | ||||
|             Console.WriteLine($"Download has {((download_status == 2) ? "been cancelled" : "failed")}."); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // The event that will fire whenever the progress of the WebClient is changed | ||||
|         // Progress event used by DownloadFile() | ||||
|         static void DownloadProgress(object sender, DownloadProgressChangedEventArgs e) | ||||
|         { | ||||
|             if (cancel_requested) | ||||
|  | @ -671,23 +833,70 @@ namespace pollock | |||
|             in_progress = true; | ||||
| 
 | ||||
|             speed = (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds); | ||||
|             Console.SetCursorPosition(0, Console.CursorTop); | ||||
|             Console.Write($" {e.ProgressPercentage.ToString("000.0")} % ({speed.ToString("0.00")} KB/s)"); | ||||
|             Console.SetCursorPosition(console_x_pos, Console.CursorTop); | ||||
|             Console.Write($"{e.ProgressPercentage.ToString("0.0"), 5}% ({speed.ToString("0.00")} KB/s)"); | ||||
|             in_progress = false; | ||||
|         } | ||||
| 
 | ||||
|         // The event that will trigger when the WebClient is completed | ||||
|         // Completed event used by DownloadFile() | ||||
|         static void DownloadCompleted(object sender, AsyncCompletedEventArgs e) | ||||
|         { | ||||
|             if (!e.Cancelled) | ||||
|             { | ||||
|                 Console.SetCursorPosition(0, Console.CursorTop); | ||||
|                 Console.Write($" 100.0 % ({speed.ToString("0.00")} KB/s)"); | ||||
|             } | ||||
|             Console.SetCursorPosition(console_x_pos, Console.CursorTop); | ||||
|             sw.Reset(); | ||||
|             download_status = (e.Cancelled) ? 2 : 1; | ||||
|             if (e.Error != null) | ||||
|             { | ||||
|                 Console.Write("Error: " + e.Error.Message); | ||||
|                 download_status = 3; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.Write($"{100.0d.ToString("0.0"),5}% ({speed.ToString("0.00")} KB/s) {(e.Cancelled ? "CANCELLED" : "DONE")}"); | ||||
|                 download_status = (e.Cancelled) ? 2 : 1; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Prompt a user for a Y/N question. | ||||
|         /// </summary> | ||||
|         /// <param name="question">The question string.</param> | ||||
|         /// <returns>true if the user answered 'Y'.</returns> | ||||
|         static bool PromptForQuestion(string question) | ||||
|         { | ||||
|             ConsoleKey response; | ||||
|             do | ||||
|             { | ||||
|                 Console.Write(question + " [y/n] "); | ||||
|                 console_x_pos = Console.CursorLeft - 6; | ||||
|                 response = Console.ReadKey(false).Key; | ||||
|                 if (response != ConsoleKey.Enter) | ||||
|                     Console.WriteLine(); | ||||
|             } while (response != ConsoleKey.Y && response != ConsoleKey.N); | ||||
|             // Flush | ||||
|             while (Console.KeyAvailable) | ||||
|                 Console.ReadKey(true); | ||||
|             return (response == ConsoleKey.Y); | ||||
|         } | ||||
| 
 | ||||
|         // Event handler for FileSystemWatcher. As usual, this is a completely BACKWARDS | ||||
|         // implementation by Microsoft that has to be worked areoun with timers and stuff... | ||||
|         private static void OnChanged(object source, FileSystemEventArgs e) | ||||
|         { | ||||
|             if (in_on_change) | ||||
|                 return; | ||||
|             in_on_change = true; | ||||
|             DateTime file_changed_time = File.GetLastWriteTime(e.FullPath); | ||||
|             if (file_changed_time >= last_changed.AddMilliseconds(250)) | ||||
|             { | ||||
|                 last_changed = file_changed_time; | ||||
|                 Console.WriteLine("File " + e.FullPath + " was edited at " + file_changed_time.ToLongTimeString()); | ||||
|                 UpdateLocFile(ParsePoFile(e.FullPath)); | ||||
|             } | ||||
|             in_on_change = false; | ||||
|         } | ||||
| 
 | ||||
|         // | ||||
|         // Main entrypoint. | ||||
|         // | ||||
|         static void Main(string[] args) | ||||
|         { | ||||
|             Console.OutputEncoding = System.Text.Encoding.UTF8; | ||||
|  | @ -696,21 +905,92 @@ namespace pollock | |||
|                 cancel_requested = true; | ||||
|             }; | ||||
| 
 | ||||
|             Console.WriteLine($"{app_name} {app_version} - Poedit to rufus.loc conversion utility"); | ||||
|             Console.WriteLine($"{app_name} {version_str} - Poedit to rufus.loc conversion utility"); | ||||
|             Console.WriteLine(); | ||||
| 
 | ||||
|             var path = @"C:\pollock"; | ||||
|             var loc = path + @"\download.loc"; | ||||
|             string loc_url = "https://github.com/pbatard/rufus/raw/master/res/localization/rufus.loc"; | ||||
|             string ver_url = "https://rufus.ie/Loc.ver"; | ||||
|             string rufus_url = null; | ||||
|             string rufus_file = null; | ||||
|             string download_url = null; | ||||
|             string po_file = null; | ||||
|             int[] update_version = new int[2]; | ||||
| 
 | ||||
|             // Download the loc file | ||||
|             //var url = "https://github.com/pbatard/rufus/raw/master/res/localization/rufus.loc"; | ||||
|             //if (!DownloadFile(url, loc)) | ||||
|             //    goto Exit; | ||||
|             // Check for updates of this application | ||||
|             var ver = DownloadString(ver_url); | ||||
|             if (ver == null) | ||||
|             { | ||||
|                 Console.WriteLine("ERROR: Could not access latest application data."); | ||||
|                 goto Exit; | ||||
|             } | ||||
|             foreach (var line in ver.Split('\n')) | ||||
|             { | ||||
|                 var parts = line.Split('='); | ||||
|                 if (parts.Count() < 2) | ||||
|                     continue; | ||||
|                 switch(parts[0].Trim()) | ||||
|                 { | ||||
|                     case "version": | ||||
|                         Int32.TryParse(parts[1].Split('.')[0], out update_version[0]); | ||||
|                         Int32.TryParse(parts[1].Split('.')[1], out update_version[1]); | ||||
|                         break; | ||||
|                     case "download_url": | ||||
|                         download_url = parts[1].Trim(); | ||||
|                         break; | ||||
|                     case "rufus_url": | ||||
|                         rufus_url = parts[1].Trim(); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Download new version | ||||
|             if ((update_version[0] > version[0]) || ((update_version[0] == version[0]) && (update_version[1] > version[1]))) | ||||
|             { | ||||
|                 Console.WriteLine(); | ||||
|                 if (PromptForQuestion("A new version of this application is available! Do you want to download it?")) | ||||
|                 { | ||||
|                     if (DownloadFile(download_url)) | ||||
|                     { | ||||
|                         Console.WriteLine("Now re-launch this program using the latest version."); | ||||
|                         goto Exit; | ||||
|                     } | ||||
|                     Console.WriteLine("Download failed."); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (rufus_url != null) | ||||
|             { | ||||
|                 // Download the latest version of Rufus to use for translations | ||||
|                 rufus_file = rufus_url.Split('/').Last(); | ||||
|                 Console.Write($"Checking for the presence of '{rufus_file}'... "); | ||||
|                 if (File.Exists(rufus_file)) | ||||
|                 { | ||||
|                     Console.WriteLine("FOUND"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     var rufus_name = rufus_url.Split('/').Last(); | ||||
|                     Console.WriteLine("MISSING"); | ||||
|                     Console.WriteLine($"{rufus_name} doesn't exist in your translation directory."); | ||||
|                     Console.WriteLine("This is the required version to validate your changes."); | ||||
|                     if (PromptForQuestion($"Do you want to download {rufus_name}?")) { | ||||
|                         Console.SetCursorPosition(console_x_pos, Console.CursorTop - 1); | ||||
|                         DownloadFile(rufus_url); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Download the latest loc file | ||||
|             Console.Write("Downloading the latest loc file... "); | ||||
|             if (!DownloadFile(loc_url)) | ||||
|                 goto Exit; | ||||
| 
 | ||||
|             var loc_file = loc_url.Split('/').Last(); | ||||
|             // Convert to CRLF and get all the language ids | ||||
|             var lines = File.ReadAllLines(loc); | ||||
|             var lines = File.ReadAllLines(loc_file); | ||||
|             string id = "", name = ""; | ||||
|             var list = new List<string[]>(); | ||||
|             using (var writer = new StreamWriter(loc, false, encoding)) | ||||
|             using (var writer = new StreamWriter(loc_file, false, encoding)) | ||||
|             { | ||||
|                 foreach (var line in lines) | ||||
|                 { | ||||
|  | @ -722,8 +1002,7 @@ namespace pollock | |||
|                     } | ||||
|                     else if (line.StartsWith("v ")) | ||||
|                     { | ||||
|                         if (id != "en-US") | ||||
|                             list.Add(new string[] { name, id, line.Substring(2) }); | ||||
|                         list.Add(new string[] { name, id, line.Substring(2) }); | ||||
|                     } | ||||
|                     writer.WriteLine(line); | ||||
|                 } | ||||
|  | @ -733,21 +1012,21 @@ Menu: | |||
|             Console.WriteLine(); | ||||
|             Console.WriteLine("Please enter the number of the language you want to edit or 'q' to quit:"); | ||||
|             Console.WriteLine(); | ||||
|             int split = (list.Count + 1) / 2; | ||||
|             for (int i = 0; i < split; i++) | ||||
|             int split = list.Count / 2; | ||||
|             for (int i = 1; i < split + 1; i++) | ||||
|             { | ||||
|                 name = $"{list[i][0]} ({list[i][1]})"; | ||||
|                 Console.Write($"[{(i+1).ToString("00")}] {name,-29} (v{list[i][2]})"); | ||||
|                 Console.Write($"[{i.ToString("00")}] {name,-29} {$"(v{list[i][2]})",-7}"); | ||||
|                 name = $"{list[i + split][0]} ({list[i + split][1]})"; | ||||
|                 Console.WriteLine($"  |  [{(i + 1 + split).ToString("00")}] {name,-29} (v{list[i + split][2]})"); | ||||
|                 Console.WriteLine($"  |  [{(i + split).ToString("00")}] {name,-29} {$"(v{list[i + split][2]})",-7}"); | ||||
|             } | ||||
|             Console.WriteLine(); | ||||
| 
 | ||||
| Retry: | ||||
|             string input = Console.ReadLine(); | ||||
|             if (input.StartsWith("q")) | ||||
|             if ((input == null) || (input.StartsWith("q"))) | ||||
|                 goto Exit; | ||||
|             if (!Int32.TryParse(input, out int number) || (number <= 0) || (number > list.Count)) | ||||
|             if (!Int32.TryParse(input, out int index) || (index <= 0) || (index > list.Count)) | ||||
|             { | ||||
|                 if (input.StartsWith("m")) | ||||
|                     goto Menu; | ||||
|  | @ -755,28 +1034,98 @@ Retry: | |||
|                 goto Retry; | ||||
|             } | ||||
| 
 | ||||
|             number--; | ||||
|             Console.WriteLine($"{list[number][0]} was selected"); | ||||
|             CreatePoFiles(path, ParseLocFile(path, list[number][1])); | ||||
|             Console.SetCursorPosition(0, Console.CursorTop - 1); | ||||
|             Console.WriteLine($"{list[index][0]} was selected."); | ||||
|             Console.WriteLine(); | ||||
|             po_file = $"{list[index][1]}.po"; | ||||
| 
 | ||||
|             // NB: Can find PoEdit from Computer\HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache | ||||
|             Language old_en_US = null; | ||||
|             if (list[index][2] == list[0][2]) | ||||
|             { | ||||
|                 Console.WriteLine("Note: This language is already at the most recent version!"); | ||||
|                 if (!PromptForQuestion("Do you still want to edit it?")) | ||||
|                     goto Exit; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var old_loc_file = $"rufus-{list[index][2]}.loc"; | ||||
|                 Console.WriteLine($"Note: This language is at v{list[index][2]} but the English base it at v{list[0][2]}."); | ||||
|                 Console.Write($"Checking for the presence of '{old_loc_file}' to compute the differences... "); | ||||
|                 if (File.Exists(old_loc_file)) | ||||
|                 { | ||||
|                     Console.WriteLine("FOUND"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Console.WriteLine("MISSING"); | ||||
|                     Console.Write($"Downloading '{old_loc_file}'... "); | ||||
|                     var url = "https://github.com/pbatard/rufus/releases/tag/v" + list[index][2]; | ||||
|                     var str = DownloadString(url); | ||||
|                     if (str == null) | ||||
|                         goto Exit; | ||||
|                     var sha = str.Substring(str.IndexOf("/pbatard/rufus/commit/") + 22, 40); | ||||
|                     url = "https://github.com/pbatard/rufus/raw/" + sha + "/res/localization/rufus.loc"; | ||||
|                     if (!DownloadFile(url, old_loc_file)) | ||||
|                         goto Exit; | ||||
|                 } | ||||
|                 var old_langs = ParseLocFile(old_loc_file, "en-US"); | ||||
|                 if ((old_langs == null) || (old_langs.Count != 1)) | ||||
|                 { | ||||
|                     Console.WriteLine("Error: Unable to get en-US data from previous loc file."); | ||||
|                     goto Exit; | ||||
|                 } | ||||
|                 old_en_US = old_langs[0]; | ||||
|             } | ||||
| 
 | ||||
|             //CreatePoFiles(path, ParseLocFile(@"C:\rufus\res\localization")); | ||||
|             if (CreatePoFiles(ParseLocFile(loc_file, list[index][1]), old_en_US) != 1) | ||||
|             { | ||||
|                 Console.WriteLine("Failed to create PO file"); | ||||
|                 goto Exit; | ||||
|             } | ||||
| 
 | ||||
|             //var en_US = ParsePoFile(path + @"\rufus.pot"); | ||||
|             //var fr_FR = ParsePoFile(path + @"\fr-FR.po"); | ||||
|             //var ar_SA = ParsePoFile(path + @"\ar-SA.po"); | ||||
|             //var vi_VN = ParsePoFile(path + @"\vi-VN.po"); | ||||
|             //List<Language> list = new List<Language>(); | ||||
|             //list.Add(en_US); | ||||
|             //list.Add(ar_SA); | ||||
|             //list.Add(fr_FR); | ||||
|             //list.Add(vi_VN); | ||||
|             //SaveLocFile(path, list); | ||||
|             //            UpdateLocFile(path + @"\test", fr_FR); | ||||
|             // Watch for file modifications | ||||
|             FileSystemWatcher watcher = new FileSystemWatcher(); | ||||
|             watcher.Path = app_path; | ||||
|             watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite; | ||||
|             watcher.Filter = po_file; | ||||
|             watcher.Changed += new FileSystemEventHandler(OnChanged); | ||||
|             watcher.EnableRaisingEvents = true; | ||||
| 
 | ||||
|             // Open the file in PoEdit if we can | ||||
|             var poedit = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Poedit\Poedit.exe"; | ||||
|             if (File.Exists(poedit)) | ||||
|             { | ||||
|                 Console.WriteLine(); | ||||
|                 //                Console.WriteLine("Please press any key to launch Poedit and edit the PO file."); | ||||
|                 Console.WriteLine("*************************************************************************************"); | ||||
|                 Console.WriteLine($"* The {list[index][0]} translation file is now ready to be edited in Poedit."); | ||||
|                 Console.WriteLine("* Please look for any entries highlited in red: They are the ones requiring an update."); | ||||
|                 Console.WriteLine("*"); | ||||
|                 Console.WriteLine("* Whenever you save your changes in Poedit, 'rufus.loc' will be updated for testing"); | ||||
|                 Console.WriteLine($"* with '{rufus_file}'. >>>PLEASE MAKE SURE YOU DON'T CLOSE THIS PROGRAM!<<<"); | ||||
|                 Console.WriteLine("* When you are done editing your translation, simply close Poedit."); | ||||
|                 Console.WriteLine("*************************************************************************************"); | ||||
|                 WaitForKey("Press any key to launch Poedit..."); | ||||
| 
 | ||||
|                 Process ExternalProcess = new Process(); | ||||
|                 ExternalProcess.StartInfo.FileName = poedit; | ||||
|                 ExternalProcess.StartInfo.WorkingDirectory = app_path; | ||||
|                 ExternalProcess.StartInfo.Arguments = $"{list[index][1]}.po"; | ||||
|                 ExternalProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized; | ||||
|                 ExternalProcess.Start(); | ||||
|                 Console.SetCursorPosition(0, Console.CursorTop - 1); | ||||
|                 Console.WriteLine("Running Poedit...                "); | ||||
|                 ExternalProcess.WaitForExit(); | ||||
|                 Console.WriteLine("Poedit was closed."); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.WriteLine("Poedit was not found. You will have to launch it and open the"); | ||||
|                 Console.WriteLine($"'{app_path + list[index][1]}.po' file manually."); | ||||
|             } | ||||
| 
 | ||||
| Exit: | ||||
|             WaitForKey(); | ||||
|             WaitForKey("Press any key to exit..."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -91,7 +91,7 @@ | |||
| # http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-LCID%5D.pdf | ||||
| # for the LCID (0x####) codes you should use | ||||
| l "en-US" "English (English)" 0x0409, 0x0809, 0x0c09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x3809, 0x3c09, 0x4009, 0x4409, 0x4809 | ||||
| v 1.0.23 | ||||
| v 3.2 | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
| t IDS_DRIVE_PROPERTIES_TXT "Drive Properties" | ||||
|  | @ -571,7 +571,7 @@ t MSG_306 "Fast-zeroing drive: %0.1f%% completed" | |||
| 
 | ||||
| l "ar-SA" "Arabic (العربية)" 0x0401, 0x0801, 0x0c01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001 | ||||
| a "r" | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -982,7 +982,7 @@ t MSG_305 "إستخدام هذا الخيار لبيان م إذا كنت تري | |||
| 
 | ||||
| ################################################################################ | ||||
| l "az-AZ" "Azerbaijani (Azərbaycanca)" 0x042c, 0x782c | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -1393,7 +1393,7 @@ t MSG_305 "Windows'u başqa bir diskə yükləmək üçün bu cihazı istifadə | |||
| 
 | ||||
| ###################################################################### | ||||
| l "bg-BG" "Bulgarian (Български)" 0x0402 | ||||
| v 1.0.22 | ||||
| v 2.16 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -1784,7 +1784,7 @@ t MSG_118 "Windows To Go (Windows за USB Flash устройство)" | |||
| 
 | ||||
| ################################################################################ | ||||
| l "zh-CN" "Chinese Simplified (简体中文)" 0x0804, 0x1004 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -2179,7 +2179,7 @@ t MSG_305 "请选择您希望将 Windows 安装至其他驱动器,还是直接 | |||
| 
 | ||||
| ################################################################################ | ||||
| l "zh-TW" "Chinese Traditional (正體中文)" 0x0404, 0x0c04, 0x1404, 0x7c04 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -2557,7 +2557,7 @@ t MSG_305 "是否要使用此裝置來安裝 Windows 在另一個磁碟上," | |||
| 
 | ||||
| ################################################################################ | ||||
| l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -2965,7 +2965,7 @@ t MSG_305 "Ovom opcijom naznačite ako želite koristiti ovaj uređaj kako bi in | |||
| 
 | ||||
| ################################################################################ | ||||
| l "cs-CZ" "Czech (Čeština)" 0x0405 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -3375,7 +3375,7 @@ t MSG_305 "Touto volbou označte, zda chcete toto zařízení používat k insta | |||
| 
 | ||||
| ################################################################################ | ||||
| l "da-DK" "Danish (Dansk)" 0x0406 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -3787,7 +3787,7 @@ t MSG_305 "Brug dette alternativ for at angive om du vil bruge denne enhed til a | |||
| 
 | ||||
| ################################################################################ | ||||
| l "nl-NL" "Dutch (Nederlands)" 0x0413, 0x0813 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -4190,7 +4190,7 @@ t MSG_305 "Gebruik deze optie om aan te geven of u dit apparaat wilt gebruiken o | |||
| 
 | ||||
| ################################################################################ | ||||
| l "fi-FI" "Finnish (Suomi)" 0x040B | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -4599,7 +4599,7 @@ t MSG_305 "Käytä tätä vaihtoehtoa valitaksesi haluatko käyttää valittua l | |||
| 
 | ||||
| ################################################################################ | ||||
| l "fr-FR" "French (Français)" 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -5012,7 +5012,7 @@ t MSG_305 "Utilisez cette option pour indiquer si vous voulez utiliser ce périp | |||
| 
 | ||||
| ################################################################################ | ||||
| l "de-DE" "German (Deutsch)" 0x0407, 0x0807, 0x0c07, 0x1007, 0x1407 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -5407,7 +5407,7 @@ t MSG_305 "Wollen Sie Windows auf einem anderen Laufwerk installieren oder Windo | |||
| 
 | ||||
| ################################################################################ | ||||
| l "el-GR" "Greek (Ελληνικά)" 0x0408 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -5823,7 +5823,7 @@ t MSG_305 "Επιλέξτε αυτό αν θέλετε να χρησιμοποι | |||
| ################################################################################ | ||||
| l "he-IL" "Hebrew (עברית)" 0x040d | ||||
| a "r" | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -6238,7 +6238,7 @@ t MSG_305 "ניתן להשתמש באפשרות זו כדי לציין האם ב | |||
| 
 | ||||
| ################################################################################ | ||||
| l "hu-HU" "Hungarian (Magyar)" 0x040e | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -6649,7 +6649,7 @@ t MSG_305 "Ezt a lehetőséget arra használd, hogy jelezd, ezt az eszközt szer | |||
| 
 | ||||
| ################################################################################ | ||||
| l "id-ID" "Indonesian (Bahasa Indonesia)" 0x0421 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -7062,7 +7062,7 @@ t MSG_305 "Gunakan opsi ini jika Anda ingin menggunakan perangkat ini untuk meng | |||
| 
 | ||||
| ################################################################################ | ||||
| l "it-IT" "Italian (Italiano)" 0x0410, 0x0810 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -7474,7 +7474,7 @@ t MSG_305 "Usa questa opzione per indicare se vuoi usare questa unità per insta | |||
| 
 | ||||
| ###################################################################### | ||||
| l "ja-JP" "Japanese (日本語)" 0x0411 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -7902,7 +7902,7 @@ t MSG_305 "このデバイスを使用して別のディスクにWindowsをイ | |||
| 
 | ||||
| ################################################################################ | ||||
| l "ko-KR" "Korean (한국어)" 0x0412 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -8313,7 +8313,7 @@ t MSG_305 "이 장치를 사용하여 다른 디스크에 Windows를 설치하 | |||
| 
 | ||||
| ################################################################################ | ||||
| l "lv-LV" "Latvian (Latviešu)" 0x0426 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -8721,7 +8721,7 @@ t MSG_305 "Izmantojiet šo opciju, lai norādīt vai vēlaties izmantot ierīci | |||
| 
 | ||||
| ################################################################################ | ||||
| l "lt-LT" "Lithuanian (Lietuvių)" 0x0427 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -9137,7 +9137,7 @@ t MSG_305 "Šią parinktį naudokite norėdami nurodyti ar naudosite šį įreng | |||
| 
 | ||||
| ################################################################################ | ||||
| l "ms-MY" "Malay (Bahasa Malaysia)" 0x043e, 0x083e | ||||
| v 1.0.19 | ||||
| v 2.5 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -9515,7 +9515,7 @@ t MSG_286 "Mensifarkan pemacu: %0.1f%% selesai" | |||
| 
 | ||||
| ################################################################################ | ||||
| l "nb-NO" "Norwegian (Norsk)" 0x0414 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -9929,7 +9929,7 @@ t MSG_305 "Bruk dette alternativet for å angi om du vil bruke denne enheten til | |||
| ################################################################################ | ||||
| l "fa-IR" "Persian (فارسی)" 0x0429 | ||||
| a "r" | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -10358,7 +10358,7 @@ t MSG_305 "با استفاده از این گزینه مشخص کنید که آ | |||
| 
 | ||||
| ################################################################################ | ||||
| l "pl-PL" "Polish (Polski)" 0x0415 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -10772,7 +10772,7 @@ t MSG_305 "Użyj tej opcji aby wskazać, czy chcesz użyć tego dysku do instala | |||
| 
 | ||||
| ################################################################################ | ||||
| l "pt-BR" "Portuguese Brazilian (Português do Brasil)" 0x0416 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -11194,7 +11194,7 @@ t MSG_305 "Use esta opção caso queira instalar o Windows neste dispositivo ou | |||
| 
 | ||||
| ################################################################################ | ||||
| l "pt-PT" "Portuguese Standard (Português)" 0x0816 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -11611,7 +11611,7 @@ t MSG_305 "Usar esta opção se pretende utilizar este dispositivo para instalar | |||
| 
 | ||||
| ################################################################################ | ||||
| l "ro-RO" "Romanian (Română)" 0x0418, 0x0818 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -12021,7 +12021,7 @@ t MSG_305 "Utilizaţi această opţiune dacă doriţi să utilizaţi acest dispo | |||
| 
 | ||||
| ################################################################################ | ||||
| l "ru-RU" "Russian (Русский)" 0x0419, 0x0819 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -12426,7 +12426,7 @@ t MSG_305 "Используйте этот параметр, чтобы указ | |||
| 
 | ||||
| ################################################################################ | ||||
| l "sr-SP" "Serbian (Srpski)" 0x241a, 0x081a, 0x181a, 0x2c1a, 0x701a, 0x7c1a | ||||
| v 1.0.22 | ||||
| v 2.16 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -12816,7 +12816,7 @@ t MSG_117 "Standardna instalacija Windows-a" | |||
| 
 | ||||
| ################################################################################ | ||||
| l "sk-SK" "Slovak (Slovensky)" 0x041B | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -13229,7 +13229,7 @@ t MSG_305 "Použite túto možnosť, ak chcete použiť toto zariadenie na inšt | |||
| 
 | ||||
| ################################################################################ | ||||
| l "sl-SI" "Slovenian (Slovenščina)" 0x0424 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -13640,7 +13640,7 @@ t MSG_305 "Tu izberete, ali želite uporabiti to napravo, da bi namestili operac | |||
| 
 | ||||
| ################################################################################ | ||||
| l "es-ES" "Spanish (Español)" 0x040a, 0x080a, 0x0c0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x540a, 0x580a | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -14056,7 +14056,7 @@ t MSG_305 "Use esta opción para indicar si desea usar este dispositivo para ins | |||
| 
 | ||||
| ################################################################################ | ||||
| l "sv-SE" "Swedish (Svenska)" 0x041d, 0x081d | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -14465,7 +14465,7 @@ t MSG_305 "Använd det här alternativet om du vill använda den här enheten f | |||
| 
 | ||||
| ################################################################################ | ||||
| l "th-TH" "Thai (ไทย)" 0x041e | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -14876,7 +14876,7 @@ t MSG_305 "เลือกตัวเลือกนี้หากต้อง | |||
| 
 | ||||
| ################################################################################ | ||||
| l "tr-TR" "Turkish (Türkçe)" 0x041F | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -15292,7 +15292,7 @@ t MSG_305 "Windows'u başka bir diske yüklemek için bu cihazı kullanmak istey | |||
| 
 | ||||
| ################################################################################ | ||||
| l "uk-UA" "Ukrainian (Українська)" 0x0422 | ||||
| v 1.0.23 | ||||
| v 3.0 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  | @ -15702,7 +15702,7 @@ t MSG_305 "Використовуйте цей параметр, щоб вказ | |||
| 
 | ||||
| ################################################################################ | ||||
| l "vi-VN" "Vietnamese (Tiếng Việt)" 0x042A | ||||
| v 1.0.22 | ||||
| v 2.16 | ||||
| b "en-US" | ||||
| 
 | ||||
| g IDD_DIALOG | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue