[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'
- '**/*.cs'
- '**/*.md'
- '**/*.rc'
- '**/*.sh'
- '**/*.txt'
- '**/*.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.
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

View File

@ -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...");
}
}
}

View File

@ -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

View File

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