Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkenneth.skovhede@gmail.com <kenneth.skovhede@gmail.com@59da171f-624f-0410-aa54-27559c288bec>2011-02-08 22:04:47 +0300
committerkenneth.skovhede@gmail.com <kenneth.skovhede@gmail.com@59da171f-624f-0410-aa54-27559c288bec>2011-02-08 22:04:47 +0300
commit97fdb5857c21d86c947d741ac72e7b34cca1c7ec (patch)
tree0fb4066f24a15d62850d973e7960b15481695948 /BuildTools
parent96e04a49ad5d1971cd5496eca473e4ad0bd5a3aa (diff)
Updated the LocalizationTool to support import/export via CSV files.
git-svn-id: https://duplicati.googlecode.com/svn/trunk@688 59da171f-624f-0410-aa54-27559c288bec
Diffstat (limited to 'BuildTools')
-rw-r--r--BuildTools/LocalizationTool/LocalizationTool/CSVReader.cs103
-rw-r--r--BuildTools/LocalizationTool/LocalizationTool/LocalizationTool.csproj1
-rw-r--r--BuildTools/LocalizationTool/LocalizationTool/Program.cs173
3 files changed, 271 insertions, 6 deletions
diff --git a/BuildTools/LocalizationTool/LocalizationTool/CSVReader.cs b/BuildTools/LocalizationTool/LocalizationTool/CSVReader.cs
new file mode 100644
index 000000000..a9d26f18b
--- /dev/null
+++ b/BuildTools/LocalizationTool/LocalizationTool/CSVReader.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace LocalizationTool
+{
+ public class CSVReader : IDisposable
+ {
+ private System.IO.StreamReader m_reader;
+
+ public CSVReader(string filename)
+ {
+ m_reader = new System.IO.StreamReader(filename, System.Text.Encoding.UTF8, true);
+ }
+
+ public List<string> AdvanceLine()
+ {
+ bool inQuote = false;
+ StringBuilder sb = new StringBuilder();
+ do
+ {
+ string line = m_reader.ReadLine();
+ if (line == null)
+ {
+ if (sb.Length == 0)
+ return null;
+ else
+ throw new Exception("Unexpected EOF, buffer was: " + sb.ToString());
+ }
+
+ sb.AppendLine(line);
+
+ foreach (char c in line)
+ if (c == '"')
+ inQuote = !inQuote;
+ } while (inQuote);
+
+ string txt = sb.ToString();
+
+ if (txt.EndsWith("\r\n"))
+ txt = txt.Substring(0, txt.Length - 2);
+ else if (txt.EndsWith("\r\n"))
+ txt = txt.Substring(0, txt.Length - 2);
+ else if (txt.EndsWith("\n"))
+ txt = txt.Substring(0, txt.Length - 1);
+ else if (txt.EndsWith("\r"))
+ txt = txt.Substring(0, txt.Length - 1);
+
+
+ inQuote = false;
+ int ix = 0;
+ List<string> result = new List<string>();
+ for(int i = 0; i < txt.Length; i++)
+ if (inQuote)
+ {
+ if (txt[i] == '"')
+ inQuote = false;
+ }
+ else
+ {
+ if (txt[i] == '"')
+ inQuote = true;
+ else if (txt[i] == ',')
+ {
+ result.Add(CleanString(txt.Substring(ix, i - ix)));
+ ix = i + 1;
+ }
+ }
+
+ if (inQuote)
+ throw new Exception("Failed to parse line: " + txt);
+
+ if (ix != txt.Length)
+ result.Add(CleanString(txt.Substring(ix)));
+
+ return result;
+ }
+
+ private string CleanString(string v)
+ {
+ //v = v.Trim();
+
+ if (v.StartsWith("\"") && v.EndsWith("\""))
+ return v.Substring(1, v.Length - 2).Replace("\"\"", "\"");
+ else
+ return v;
+ }
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ if (m_reader != null)
+ {
+ m_reader.Dispose();
+ m_reader = null;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/BuildTools/LocalizationTool/LocalizationTool/LocalizationTool.csproj b/BuildTools/LocalizationTool/LocalizationTool/LocalizationTool.csproj
index 9b3226d45..1ded887e5 100644
--- a/BuildTools/LocalizationTool/LocalizationTool/LocalizationTool.csproj
+++ b/BuildTools/LocalizationTool/LocalizationTool/LocalizationTool.csproj
@@ -51,6 +51,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="CSVReader.cs" />
<Compile Include="LinqHelpers.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/BuildTools/LocalizationTool/LocalizationTool/Program.cs b/BuildTools/LocalizationTool/LocalizationTool/Program.cs
index 8226ad0a1..663823d4e 100644
--- a/BuildTools/LocalizationTool/LocalizationTool/Program.cs
+++ b/BuildTools/LocalizationTool/LocalizationTool/Program.cs
@@ -68,6 +68,18 @@ namespace LocalizationTool
case "report":
Report(loc);
break;
+ case "export":
+ Export(loc);
+ break;
+ case "import":
+ if (args.Length != 3)
+ {
+ Console.WriteLine("missing locale identifier or input CSV file");
+ PrintUsage();
+ return;
+ }
+ Import(loc, args[2]);
+ break;
case "guiupdate":
Application.EnableVisualStyles();
Application.DoEvents();
@@ -81,6 +93,7 @@ namespace LocalizationTool
}
}
+
private static void PrintUsage()
{
Console.WriteLine("Usage: ");
@@ -91,8 +104,79 @@ namespace LocalizationTool
Console.WriteLine("LocalizationTool.exe REPORT [locale identifier]");
Console.WriteLine("LocalizationTool.exe CREATE <locale indentifier>");
Console.WriteLine("LocalizationTool.exe GUIUPDATE <locale identifier>");
+ Console.WriteLine("LocalizationTool.exe EXPORT [locale identifier]");
+ Console.WriteLine("LocalizationTool.exe IMPORT <locale identifier> <input CSV file>");
}
+ private static void Import(string loc, string p)
+ {
+ //Outer key is filename, inner key is fieldname, inner value is translated text
+ Dictionary<string, Dictionary<string, string>> values = new Dictionary<string, Dictionary<string, string>>();
+
+ using (CSVReader r = new CSVReader(p))
+ {
+ List<string> fields = null;
+ while ((fields = r.AdvanceLine()) != null)
+ if (fields.Count >= 5)
+ {
+ string filename = fields[0];
+ filename = System.IO.Path.Combine(System.IO.Path.Combine(Application.StartupPath, loc), filename);
+ string fieldkey = fields[1];
+ string origvalue = fields[3];
+ string value = fields[4];
+
+ if (value.Trim().Length == 0 || value == origvalue)
+ continue;
+
+ if (!values.ContainsKey(filename))
+ values.Add(filename, new Dictionary<string,string>());
+
+ Dictionary<string, string> l = values[filename];
+ l[fieldkey] = value;
+ }
+ }
+
+ XNamespace xmlns = "";
+ foreach (ResXFileInfo inf in GetResXList(loc))
+ {
+ if (System.IO.File.Exists(inf.TargetFile) && values.ContainsKey(inf.TargetFile))
+ {
+ XDocument targetDoc = XDocument.Load(inf.TargetFile);
+ XNode insertTarget = targetDoc.Element("root").LastNode;
+ var targetVals = targetDoc.Element("root").Elements("data").ToSafeDictionary(c => c.Attribute("name").Value, inf.TargetFile);
+ var sourceVals = values[inf.TargetFile];
+ values.Remove(inf.TargetFile);
+
+ bool updated = false;
+ foreach (var item in sourceVals)
+ if (targetVals.ContainsKey(item.Key))
+ {
+ if (targetVals[item.Key].Element("value").Value != item.Value)
+ {
+ updated = true;
+ targetVals[item.Key].Element("value").Value = item.Value;
+ }
+ }
+ else
+ {
+ updated = true;
+ insertTarget.AddAfterSelf(new XElement("data",
+ new XAttribute("name", item.Key),
+ new XAttribute(xmlns + "space", "preserve"),
+ new XElement("value", item.Value)
+ ));
+ }
+
+ if (updated)
+ targetDoc.Save(inf.TargetFile);
+ }
+ }
+
+ if (values.Count != 0)
+ throw new Exception("The following files were translated but did not exist: " + string.Join(Environment.NewLine, values.Keys.ToArray()));
+ }
+
+
public static IEnumerable<string> GetLocaleFolders(string locid)
{
if (string.IsNullOrEmpty(locid))
@@ -112,6 +196,60 @@ namespace LocalizationTool
return new string[] { locid };
}
+ private static void Export(string cultures)
+ {
+ Update(cultures);
+ Report(cultures);
+
+ foreach (string culture in GetLocaleFolders(cultures))
+ {
+ XDocument doc = XDocument.Load(System.IO.Path.Combine(Application.StartupPath, "report." + culture + ".xml"));
+ string outfile = System.IO.Path.Combine(Application.StartupPath, "report." + culture + ".csv");
+ using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outfile, false, new System.Text.UTF8Encoding(false)))
+ {
+ foreach (var file in doc.Element("root").Elements("file"))
+ {
+ string filename = file.Attribute("filename").Value.Substring(Duplicati.Library.Utility.Utility.AppendDirSeparator(Application.StartupPath).Length);
+ filename = filename.Substring(culture.Length + 1);
+
+ foreach (var item in file.Element("updated").Elements("item"))
+ WriteCSVLine(sw, filename, item.Attribute("name").Value, item.Parent.Name.LocalName, item.Element("original").Value, item.Element("translated").Value);
+
+ foreach (var item in file.Element("missing").Elements("item"))
+ WriteCSVLine(sw, filename, item.Attribute("name").Value, item.Parent.Name.LocalName, item.Value, "");
+
+ foreach (var item in file.Element("not-updated").Elements("item"))
+ WriteCSVLine(sw, filename, item.Attribute("name").Value, item.Parent.Name.LocalName, item.Value, "");
+
+ foreach (var item in file.Element("unused").Elements("item"))
+ WriteCSVLine(sw, filename, item.Attribute("name").Value, item.Parent.Name.LocalName, "", item.Value);
+ }
+ }
+ }
+ }
+
+ private static string CSV_SEPARATOR = ",";
+
+ private static void WriteCSVLine(System.IO.StreamWriter sw, string filename, string key, string status, string originalText, string translatedText)
+ {
+ sw.Write(EscapeCSVString(filename));
+ sw.Write(CSV_SEPARATOR);
+ sw.Write(EscapeCSVString(key));
+ sw.Write(CSV_SEPARATOR);
+ sw.Write(EscapeCSVString(status));
+ sw.Write(CSV_SEPARATOR);
+ sw.Write(EscapeCSVString(originalText));
+ sw.Write(CSV_SEPARATOR);
+ sw.Write(EscapeCSVString(translatedText));
+ sw.WriteLine();
+ }
+
+ private static string EscapeCSVString(string value)
+ {
+ //.Replace("\\", "\\\\").Replace("\r\n", "\\n").Replace("\r", "\\n").Replace("\n", "\\n").Replace("\t", "\\t")
+ return "\"" + value.Replace("\"", "\"\"") + "\"";
+ }
+
private static void Report(string cultures)
{
foreach (string culture in GetLocaleFolders(cultures))
@@ -195,18 +333,29 @@ namespace LocalizationTool
targetElements = targetElements.Where(filter);
}
+ //Filter the source and target before proceeding
+ sourceElements = sourceElements.Where(c => !ignores.ContainsKey(c.Element("value").Value.Trim().ToLower()) && !c.Element("value").Value.Trim().ToLower().StartsWith("..\\resources\\"));
+ targetElements = targetElements.Where(c => !ignores.ContainsKey(c.Element("value").Value.Trim().ToLower()) && !c.Element("value").Value.Trim().ToLower().StartsWith("..\\resources\\"));
+
var sourceVals = sourceElements.ToSafeDictionary(c => c.Attribute("name").Value, inf.SourceFile);
var targetVals = targetElements.ToSafeDictionary(c => c.Attribute("name").Value, inf.TargetFile);
- var missing = sourceVals.Where(c => !targetVals.ContainsKey(c.Key) && !ignores.ContainsKey(c.Value.Element("value").Value.Trim().ToLower()) && !c.Value.Element("value").Value.Trim().ToLower().StartsWith("..\\resources\\"));
- var unused = targetVals.Where(c => !sourceVals.ContainsKey(c.Key));
+
+ var missing = sourceVals.Where(c => !targetVals.ContainsKey(c.Key)).ToList();
+ var unused = targetVals.Where(c => !sourceVals.ContainsKey(c.Key)).ToList();
var notUpdated = sourceVals.Where(c =>
- !ignores.ContainsKey(c.Value.Element("value").Value.Trim().ToLower())
+ targetVals.ContainsKey(c.Key)
+ &&
+ targetVals[c.Key].Element("value").Value == c.Value.Element("value").Value).ToList();
+
+ var updated = sourceVals.Where(c =>
+ !missing.Contains(c)
&&
- !c.Value.Element("value").Value.Trim().ToLower().StartsWith("..\\resources\\")
+ !unused.Contains(c)
&&
- targetVals.ContainsKey(c.Key)
+ !notUpdated.Contains(c)
&&
- targetVals[c.Key].Element("value").Value == c.Value.Element("value").Value);
+ targetVals.ContainsKey(c.Key)
+ );
reportRoot.Add(
new XElement("file",
@@ -231,6 +380,18 @@ namespace LocalizationTool
new XAttribute("name", x.Key),
x.Value.Element("value").Value
)
+ ),
+ new XElement("updated",
+ from x in updated
+ select new XElement("item",
+ new XAttribute("name", x.Key),
+ new XElement("original",
+ x.Value.Element("value").Value
+ ),
+ new XElement("translated",
+ targetVals[x.Key].Element("value").Value
+ )
+ )
)
)
);