1
1
Fork 0
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:
Pete Batard 2018-07-14 23:39:24 +01:00
parent af9cca5fb3
commit d9d0feadb6
5 changed files with 563 additions and 213 deletions

View file

@ -12,6 +12,7 @@ skip_commits:
- '**/*.cmd' - '**/*.cmd'
- '**/*.cs' - '**/*.cs'
- '**/*.md' - '**/*.md'
- '**/*.rc'
- '**/*.sh' - '**/*.sh'
- '**/*.txt' - '**/*.txt'
- '**/*.xml' - '**/*.xml'

View file

@ -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. 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! 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_087
- *NEW* MSG_172 - *NEW* MSG_172
- *NEW* MSG_199 - *NEW* MSG_199
- *NEW* MSG_306 - *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 - 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_DRIVE_PROPERTIES_TXT "Drive Properties"
- *NEW* IDS_BOOT_SELECTION_TXT "Boot selection" - *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". 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. *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_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_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" - *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." "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) 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_288 "Missing elevated privileges"
- *NEW* MSG_289 "This application can only run with 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 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." - *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. 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" - *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") 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!!) 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 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. 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) 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" 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" - *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 " - *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?" "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_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..." - 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" - *NEW* MSG_269 "Preserve timestamps"
@ -148,7 +148,7 @@ o Version 1.0.18 (2015.09.03)
- *NEW* MSG_280 "Image selection" - *NEW* MSG_280 "Image selection"
- *NEW* MSG_281 "(Please select an image)" - *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_INSTALL "Standard Windows installation" (Main dialog)
- *NEW CONTROL* IDC_WINDOWS_TO_GO "Windows To Go" (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 Note: to see the 2 controls above displayed, you will need to load the "Windows To Go.iso" image from

View file

@ -20,9 +20,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Cache;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -58,6 +61,25 @@ namespace pollock
this.group = group; this.group = group;
this.id = id; 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 public sealed class Language
@ -67,20 +89,23 @@ namespace pollock
public string version; public string version;
public string lcid; public string lcid;
public SortedDictionary<string, List<Message>> sections; 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() public Language()
{ {
sections = new SortedDictionary<string, List<Message>>(); 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 class Pollock
{ {
private static string app_name = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; private static string app_name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Assembly.GetExecutingAssembly().GetName().Name);
private static string app_version = "v" private static int[] version = new int[2]
+ Assembly.GetEntryAssembly().GetName().Version.Major.ToString() + "." { Assembly.GetEntryAssembly().GetName().Version.Major, Assembly.GetEntryAssembly().GetName().Version.Minor };
+ Assembly.GetEntryAssembly().GetName().Version.Minor.ToString(); 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 static bool cancel_requested = false;
private const string LANG_ID = "Language"; private const string LANG_ID = "Language";
private const string LANG_NAME = "X-Rufus-LanguageName"; private const string LANG_NAME = "X-Rufus-LanguageName";
@ -88,35 +113,41 @@ namespace pollock
private const string LANG_LCID = "X-Rufus-LCID"; private const string LANG_LCID = "X-Rufus-LCID";
private static Encoding encoding = new UTF8Encoding(false); private static Encoding encoding = new UTF8Encoding(false);
private static List<string> rtl_languages = new List<string> { "ar-SA", "he-IL", "fa-IR" }; 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 WebClient wc = new WebClient();
private static DateTime last_changed = DateTime.MinValue;
private static int download_status; private static int download_status;
private static int console_x_pos;
private static bool in_progress = false; private static bool in_progress = false;
private static bool in_on_change = false;
private static double speed = 0.0f; private static double speed = 0.0f;
/// <summary> /// <summary>
/// Wait for a key to be pressed. /// Wait for a key to be pressed.
/// </summary> /// </summary>
static void WaitForKey() static void WaitForKey(string msg = null)
{ {
if (msg == null)
msg = "Press any key to continue...";
// Flush the input buffer // Flush the input buffer
while (Console.KeyAvailable) while (Console.KeyAvailable)
Console.ReadKey(true); Console.ReadKey(true);
Console.WriteLine(""); Console.WriteLine("");
Console.WriteLine("Press any key to exit..."); Console.WriteLine(msg);
Console.ReadKey(true);
while (Console.KeyAvailable)
Console.ReadKey(true); Console.ReadKey(true);
} }
/// <summary> /// <summary>
/// Import languages from an existing rufus.loc /// Import languages from an existing Rufus loc file
/// </summary> /// </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> /// <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 lines = File.ReadAllLines(file);
var rufus_pot = path + @"\rufus.pot";
var lines = File.ReadAllLines(rufus_loc);
int line_nr = 0; int line_nr = 0;
string format = "D" + (int)(Math.Log10((double)lines.Count()) + 0.99999); string format = "D" + (int)(Math.Log10((double)lines.Count()) + 0.99999);
string last_key = null; string last_key = null;
@ -126,24 +157,24 @@ namespace pollock
List<Language> langs = new List<Language>(); List<Language> langs = new List<Language>();
Language lang = null; Language lang = null;
bool skip_line = false; bool skip_line = false;
bool found_my_id = false;
Id id;
sw.Start(); if (!File.Exists(file))
if (!File.Exists(rufus_loc))
{ {
Console.Error.WriteLine($"Could not open {rufus_loc}"); Console.Error.WriteLine($"Could not open {file}");
return null; return null;
} }
Console.WriteLine($"Importing data from '{rufus_loc}':"); Console.Write($"Importing data from '{file}'... ");
foreach (var line in lines) foreach (var line in lines)
{ {
if (cancel_requested) if ((cancel_requested) || (found_my_id && skip_line))
break; break;
++line_nr; ++line_nr;
Console.SetCursorPosition(0, Console.CursorTop); //Console.SetCursorPosition(0, Console.CursorTop);
Console.Write($"[{line_nr.ToString(format)}/{lines.Count()}] "); //Console.Write($"[{line_nr.ToString(format)}/{lines.Count()}] ");
var data = line.Trim(); var data = line.Trim();
int i = data.IndexOf("#"); int i = data.IndexOf("#");
if (i > 0) if (i > 0)
@ -171,13 +202,17 @@ namespace pollock
Console.WriteLine("Error: Invalid 'l' command"); Console.WriteLine("Error: Invalid 'l' command");
return null; return null;
} }
string lid = parts[1].Replace("\"", ""); string cur_id = parts[1].Replace("\"", "");
if (id != null) if (select_id != null)
{ {
if ((!skip_line) && (id != lid) && (lid != "en-US")) if ((select_id == "en-US") && (cur_id != "en-US"))
skip_line = true; 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; skip_line = false;
if (select_id == cur_id)
found_my_id = true;
if (skip_line) if (skip_line)
break; break;
} }
@ -186,7 +221,7 @@ namespace pollock
lang = new Language(); lang = new Language();
lang.id = parts[1].Replace("\"", ""); lang.id = parts[1].Replace("\"", "");
lang.name = parts[2].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]; lang.lcid = parts[3];
for (i = 4; i < parts.Count; i++) for (i = 4; i < parts.Count; i++)
lang.lcid += " " + parts[i]; lang.lcid += " " + parts[i];
@ -223,10 +258,14 @@ namespace pollock
continue; continue;
} }
lang.sections[section_name].Add(new Message(parts[1], parts[2])); 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]; last_key = parts[1];
if (comment != null) if (comment != null)
{ {
lang.comments[last_key] = comment.Trim(); id = new Id(section_name, last_key);
lang.comments[id] = comment.Trim();
comment = null; comment = null;
} }
break; break;
@ -238,16 +277,16 @@ namespace pollock
} }
lang.sections[section_name].Last().str += data; lang.sections[section_name].Last().str += data;
lang.sections[section_name].Last().str = lang.sections[section_name].Last().str.Replace("\"\"", ""); 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; break;
} }
} }
if (lang != null) if (lang != null)
langs.Add(lang); langs.Add(lang);
sw.Stop(); Console.WriteLine(cancel_requested ? "CANCELLED" : "DONE");
Console.WriteLine($"{(cancel_requested ? "CANCELLED after" : "DONE in")}" +
$" {sw.ElapsedMilliseconds / 1000.0}s.");
sw.Reset();
return langs; return langs;
} }
@ -255,37 +294,67 @@ namespace pollock
/// <summary> /// <summary>
/// Create .po/.pot files from a list of Language elements. /// Create .po/.pot files from a list of Language elements.
/// </summary> /// </summary>
/// <param name="path">The path where the .po/.pot files should be created.</param> /// <param name="langs">A lits of Language objects to process.</param>
/// <param name="langs">A lits of Languages elements</param> /// <param name="old_en_US">(Optional) A previous version of en-US to use for comparison.</param>
/// <returns>true on success, false on error.</returns> /// <param name="path">(Optional) The path where the .po/.pot files should be created.</param>
static bool CreatePoFiles(string path, List<Language> langs, bool merge_pot = false) /// <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) if (langs == null)
return false; return 0;
var en_US = langs.Find(x => x.id == "en-US"); var cur_en_US = langs.Find(x => x.id == "en-US");
if (en_US == null) if (cur_en_US == null)
return false; 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 // Build the list of all the current IDs we need to process
foreach (var section in en_US.sections) 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)) if (!old_en_US.id_to_str.ContainsKey(id))
msg_to_ids[msg.str].Add(new Id(section.Key, msg.id)); {
else // ID is not present in old -> added
msg_to_ids.Add(msg.str, new List<Id>() { new Id(section.Key, msg.id) }); //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) foreach (var lang in langs)
{ {
bool is_pot = (lang.id == "en-US"); bool is_pot = (lang.id == "en-US");
var target = path + @"\" + (is_pot ? "rufus.pot" : lang.id + ".po"); // Don't create the .pot if we are producing a merge
Console.WriteLine($"Creating '{target}'"); 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)) using (var writer = new StreamWriter(target, false, encoding))
{ {
@ -311,50 +380,59 @@ namespace pollock
var dupes = new List<string>(); 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
var en_str = en_US.sections[section.Key].Find(x => x.id == msg.id).str;
// Handle duplicates
if (dupes.Contains(en_str)) if (dupes.Contains(en_str))
continue; continue;
writer.WriteLine(); writer.WriteLine();
foreach (var id in msg_to_ids[en_str])
{ var cid_list = cur_en_US.id_to_str.Where(x => x.Value == en_str).Select(x => x.Key);
if (id.group == "MSG") foreach (var cid in cid_list)
writer.WriteLine($"#. • {id.id}"); writer.WriteLine($"#. • {cid}");
else if (cid_list.Count() > 1)
writer.WriteLine($"#. • {id.group} → {id.id}");
}
if (msg_to_ids[en_str].Count > 1)
dupes.Add(en_str); dupes.Add(en_str);
if (lang.comments.ContainsKey(msg.id)) if (cur_en_US.comments.ContainsKey(id))
{ {
if (is_pot)
writer.WriteLine("#."); writer.WriteLine("#.");
foreach (var comment in lang.comments[msg.id].Split('\n')) foreach (var comment in cur_en_US.comments[id].Split('\n'))
if (comment.Trim() != "") if (comment.Trim() != "")
writer.WriteLine((is_pot ? "#. " : "# ") + comment); 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) if (is_pot)
{ {
writer.WriteLine($"msgid {msg.str}"); writer.WriteLine($"msgid {msg_str}");
writer.WriteLine("msgstr \"\""); writer.WriteLine("msgstr \"\"");
} }
else else
{ {
writer.WriteLine($"msgid {en_str}"); writer.WriteLine($"msgid {en_str}");
writer.WriteLine($"msgstr {msg.str}"); writer.WriteLine($"msgstr {msg_str}");
} }
} }
} }
nb_po_saved++;
} }
} Console.WriteLine("DONE");
Console.WriteLine("DONE."); return nb_po_saved;
return true;
} }
/// <summary> /// <summary>
@ -476,9 +554,9 @@ namespace pollock
{ {
if (comments != null) if (comments != null)
{ {
lang.comments.Add(id.id, ""); lang.comments.Add(id, "");
foreach (var comment in comments) 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 // Ignore messages that have the same translation as en-US
if (msg_data[0] == msg_data[1]) if (msg_data[0] == msg_data[1])
@ -528,9 +606,10 @@ namespace pollock
writer.WriteLine($"g {section}"); writer.WriteLine($"g {section}");
foreach (var msg in lang.sections[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() != "") if (l.Trim() != "")
writer.WriteLine($"# {l}"); writer.WriteLine($"# {l}");
} }
@ -540,16 +619,21 @@ namespace pollock
} }
/// <summary> /// <summary>
/// Create a new rufus.loc from a list of Language elements. /// Update a rufus.loc section from a language element.
/// </summary> /// </summary>
/// <param name="path">The path where the new 'rufus.loc' should be created.</param> /// <param name="lang">The Language elements to update.</param>
/// <param name="list">The list of Language elements.</param> /// <param name="path">(Optional) The path where 'rufus.loc' is located.</param>
/// <returns>true on success, false on error.</returns> /// <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) if (lang == null)
return false; 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); var lines = File.ReadAllLines(target);
using (var writer = new StreamWriter(target, false, encoding)) using (var writer = new StreamWriter(target, false, encoding))
{ {
@ -576,21 +660,25 @@ namespace pollock
/// <summary> /// <summary>
/// Create a new rufus.loc from a list of Language elements. /// Create a new rufus.loc from a list of Language elements.
/// </summary> /// </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="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> /// <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)) if ((list == null) || (list.Count == 0))
return false; return false;
var target = path + @"\rufus.loc"; if (path == null)
path = app_path;
if (!path.EndsWith("\\"))
path += '\\';
var target = path + "rufus.loc";
sw.Start(); sw.Start();
Console.WriteLine($"Creating '{target}':"); Console.WriteLine($"Creating '{target}':");
using (var writer = new StreamWriter(target, false, encoding)) 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); var sep = new String('#', notice.Length);
writer.WriteLine(sep); writer.WriteLine(sep);
writer.WriteLine(notice); writer.WriteLine(notice);
@ -620,25 +708,102 @@ namespace pollock
return true; 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; HttpStatusCode status = HttpStatusCode.NotFound;
in_progress = false; var uri = new Uri(url);
using (wc) WebRequest request = WebRequest.Create(uri);
{ request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted); request.Method = "HEAD";
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
Console.WriteLine($"Downloading {url}:");
sw.Start();
// This is soooooooo retarded. Trying to simply read a 404 response throws a 404 *exception*?!?
try try
{ {
wc.DownloadFileAsync(new Uri(url), dest); 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)
{
try
{
str = System.Text.Encoding.UTF8.GetString(wc.DownloadData(new Uri(url)));
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine("ERROR: " + e.Message); 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; return false;
} }
} }
@ -647,16 +812,13 @@ namespace pollock
Console.WriteLine(); Console.WriteLine();
if (download_status == 1) if (download_status == 1)
{
Console.WriteLine("Download complete");
return true; return true;
}
Console.WriteLine("Download has been canceled."); Console.WriteLine($"Download has {((download_status == 2) ? "been cancelled" : "failed")}.");
return false; 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) static void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{ {
if (cancel_requested) if (cancel_requested)
@ -671,23 +833,70 @@ namespace pollock
in_progress = true; in_progress = true;
speed = (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds); speed = (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds);
Console.SetCursorPosition(0, Console.CursorTop); Console.SetCursorPosition(console_x_pos, Console.CursorTop);
Console.Write($" {e.ProgressPercentage.ToString("000.0")} % ({speed.ToString("0.00")} KB/s)"); Console.Write($"{e.ProgressPercentage.ToString("0.0"), 5}% ({speed.ToString("0.00")} KB/s)");
in_progress = false; 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) static void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{ {
if (!e.Cancelled) Console.SetCursorPosition(console_x_pos, Console.CursorTop);
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write($" 100.0 % ({speed.ToString("0.00")} KB/s)");
}
sw.Reset(); sw.Reset();
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; 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) static void Main(string[] args)
{ {
Console.OutputEncoding = System.Text.Encoding.UTF8; Console.OutputEncoding = System.Text.Encoding.UTF8;
@ -696,21 +905,92 @@ namespace pollock
cancel_requested = true; 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"; string loc_url = "https://github.com/pbatard/rufus/raw/master/res/localization/rufus.loc";
var loc = path + @"\download.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 // Check for updates of this application
//var url = "https://github.com/pbatard/rufus/raw/master/res/localization/rufus.loc"; var ver = DownloadString(ver_url);
//if (!DownloadFile(url, loc)) if (ver == null)
// goto Exit; {
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 // Convert to CRLF and get all the language ids
var lines = File.ReadAllLines(loc); var lines = File.ReadAllLines(loc_file);
string id = "", name = ""; string id = "", name = "";
var list = new List<string[]>(); 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) foreach (var line in lines)
{ {
@ -722,7 +1002,6 @@ namespace pollock
} }
else if (line.StartsWith("v ")) 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); writer.WriteLine(line);
@ -733,21 +1012,21 @@ Menu:
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Please enter the number of the language you want to edit or 'q' to quit:"); Console.WriteLine("Please enter the number of the language you want to edit or 'q' to quit:");
Console.WriteLine(); Console.WriteLine();
int split = (list.Count + 1) / 2; int split = list.Count / 2;
for (int i = 0; i < split; i++) for (int i = 1; i < split + 1; i++)
{ {
name = $"{list[i][0]} ({list[i][1]})"; 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]})"; 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(); Console.WriteLine();
Retry: Retry:
string input = Console.ReadLine(); string input = Console.ReadLine();
if (input.StartsWith("q")) if ((input == null) || (input.StartsWith("q")))
goto Exit; 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")) if (input.StartsWith("m"))
goto Menu; goto Menu;
@ -755,28 +1034,98 @@ Retry:
goto Retry; goto Retry;
} }
number--; Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine($"{list[number][0]} was selected"); Console.WriteLine($"{list[index][0]} was selected.");
CreatePoFiles(path, ParseLocFile(path, list[number][1])); 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"); // Watch for file modifications
//var fr_FR = ParsePoFile(path + @"\fr-FR.po"); FileSystemWatcher watcher = new FileSystemWatcher();
//var ar_SA = ParsePoFile(path + @"\ar-SA.po"); watcher.Path = app_path;
//var vi_VN = ParsePoFile(path + @"\vi-VN.po"); watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
//List<Language> list = new List<Language>(); watcher.Filter = po_file;
//list.Add(en_US); watcher.Changed += new FileSystemEventHandler(OnChanged);
//list.Add(ar_SA); watcher.EnableRaisingEvents = true;
//list.Add(fr_FR);
//list.Add(vi_VN); // Open the file in PoEdit if we can
//SaveLocFile(path, list); var poedit = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Poedit\Poedit.exe";
// UpdateLocFile(path + @"\test", fr_FR); 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: Exit:
WaitForKey(); WaitForKey("Press any key to exit...");
} }
} }
} }

View file

@ -91,7 +91,7 @@
# http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-LCID%5D.pdf # 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 # 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 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 g IDD_DIALOG
t IDS_DRIVE_PROPERTIES_TXT "Drive Properties" 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 l "ar-SA" "Arabic (العربية)" 0x0401, 0x0801, 0x0c01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001
a "r" a "r"
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -982,7 +982,7 @@ t MSG_305 "إستخدام هذا الخيار لبيان م إذا كنت تري
################################################################################ ################################################################################
l "az-AZ" "Azerbaijani (Azərbaycanca)" 0x042c, 0x782c l "az-AZ" "Azerbaijani (Azərbaycanca)" 0x042c, 0x782c
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "bg-BG" "Bulgarian (Български)" 0x0402
v 1.0.22 v 2.16
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -1784,7 +1784,7 @@ t MSG_118 "Windows To Go (Windows за USB Flash устройство)"
################################################################################ ################################################################################
l "zh-CN" "Chinese Simplified (简体中文)" 0x0804, 0x1004 l "zh-CN" "Chinese Simplified (简体中文)" 0x0804, 0x1004
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -2179,7 +2179,7 @@ t MSG_305 "请选择您希望将 Windows 安装至其他驱动器,还是直接
################################################################################ ################################################################################
l "zh-TW" "Chinese Traditional (正體中文)" 0x0404, 0x0c04, 0x1404, 0x7c04 l "zh-TW" "Chinese Traditional (正體中文)" 0x0404, 0x0c04, 0x1404, 0x7c04
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -2557,7 +2557,7 @@ t MSG_305 "是否要使用此裝置來安裝 Windows 在另一個磁碟上,"
################################################################################ ################################################################################
l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "cs-CZ" "Czech (Čeština)" 0x0405
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "da-DK" "Danish (Dansk)" 0x0406
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "nl-NL" "Dutch (Nederlands)" 0x0413, 0x0813
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "fi-FI" "Finnish (Suomi)" 0x040B
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 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" b "en-US"
g IDD_DIALOG 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 l "de-DE" "German (Deutsch)" 0x0407, 0x0807, 0x0c07, 0x1007, 0x1407
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "el-GR" "Greek (Ελληνικά)" 0x0408
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -5823,7 +5823,7 @@ t MSG_305 "Επιλέξτε αυτό αν θέλετε να χρησιμοποι
################################################################################ ################################################################################
l "he-IL" "Hebrew (עברית)" 0x040d l "he-IL" "Hebrew (עברית)" 0x040d
a "r" a "r"
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -6238,7 +6238,7 @@ t MSG_305 "ניתן להשתמש באפשרות זו כדי לציין האם ב
################################################################################ ################################################################################
l "hu-HU" "Hungarian (Magyar)" 0x040e l "hu-HU" "Hungarian (Magyar)" 0x040e
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "id-ID" "Indonesian (Bahasa Indonesia)" 0x0421
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "it-IT" "Italian (Italiano)" 0x0410, 0x0810
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "ja-JP" "Japanese (日本語)" 0x0411
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -7902,7 +7902,7 @@ t MSG_305 "このデバイスを使用して別のディスクにWindowsをイ
################################################################################ ################################################################################
l "ko-KR" "Korean (한국어)" 0x0412 l "ko-KR" "Korean (한국어)" 0x0412
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -8313,7 +8313,7 @@ t MSG_305 "이 장치를 사용하여 다른 디스크에 Windows를 설치하
################################################################################ ################################################################################
l "lv-LV" "Latvian (Latviešu)" 0x0426 l "lv-LV" "Latvian (Latviešu)" 0x0426
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "lt-LT" "Lithuanian (Lietuvių)" 0x0427
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "ms-MY" "Malay (Bahasa Malaysia)" 0x043e, 0x083e
v 1.0.19 v 2.5
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -9515,7 +9515,7 @@ t MSG_286 "Mensifarkan pemacu: %0.1f%% selesai"
################################################################################ ################################################################################
l "nb-NO" "Norwegian (Norsk)" 0x0414 l "nb-NO" "Norwegian (Norsk)" 0x0414
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "fa-IR" "Persian (فارسی)" 0x0429
a "r" a "r"
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -10358,7 +10358,7 @@ t MSG_305 "با استفاده از این گزینه مشخص کنید که آ
################################################################################ ################################################################################
l "pl-PL" "Polish (Polski)" 0x0415 l "pl-PL" "Polish (Polski)" 0x0415
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "pt-BR" "Portuguese Brazilian (Português do Brasil)" 0x0416
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "pt-PT" "Portuguese Standard (Português)" 0x0816
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "ro-RO" "Romanian (Română)" 0x0418, 0x0818
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "ru-RU" "Russian (Русский)" 0x0419, 0x0819
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -12426,7 +12426,7 @@ t MSG_305 "Используйте этот параметр, чтобы указ
################################################################################ ################################################################################
l "sr-SP" "Serbian (Srpski)" 0x241a, 0x081a, 0x181a, 0x2c1a, 0x701a, 0x7c1a l "sr-SP" "Serbian (Srpski)" 0x241a, 0x081a, 0x181a, 0x2c1a, 0x701a, 0x7c1a
v 1.0.22 v 2.16
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -12816,7 +12816,7 @@ t MSG_117 "Standardna instalacija Windows-a"
################################################################################ ################################################################################
l "sk-SK" "Slovak (Slovensky)" 0x041B l "sk-SK" "Slovak (Slovensky)" 0x041B
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "sl-SI" "Slovenian (Slovenščina)" 0x0424
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 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" b "en-US"
g IDD_DIALOG 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 l "sv-SE" "Swedish (Svenska)" 0x041d, 0x081d
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "th-TH" "Thai (ไทย)" 0x041e
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -14876,7 +14876,7 @@ t MSG_305 "เลือกตัวเลือกนี้หากต้อง
################################################################################ ################################################################################
l "tr-TR" "Turkish (Türkçe)" 0x041F l "tr-TR" "Turkish (Türkçe)" 0x041F
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG 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 l "uk-UA" "Ukrainian (Українська)" 0x0422
v 1.0.23 v 3.0
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG
@ -15702,7 +15702,7 @@ t MSG_305 "Використовуйте цей параметр, щоб вказ
################################################################################ ################################################################################
l "vi-VN" "Vietnamese (Tiếng Việt)" 0x042A l "vi-VN" "Vietnamese (Tiếng Việt)" 0x042A
v 1.0.22 v 2.16
b "en-US" b "en-US"
g IDD_DIALOG g IDD_DIALOG

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326 IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 3.2.1335" CAPTION "Rufus 3.2.1336"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0 FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,2,1335,0 FILEVERSION 3,2,1336,0
PRODUCTVERSION 3,2,1335,0 PRODUCTVERSION 3,2,1336,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://akeo.ie" VALUE "Comments", "https://akeo.ie"
VALUE "CompanyName", "Akeo Consulting" VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "3.2.1335" VALUE "FileVersion", "3.2.1336"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2018 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2018 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus-3.2.exe" VALUE "OriginalFilename", "rufus-3.2.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.2.1335" VALUE "ProductVersion", "3.2.1336"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"