合并 2 个不同的 RESX 文件 - Windows ASP.NET
Consolidate 2 different RESX files - Windows ASP.NET
我们有几个来自公司几个不同项目的 RESX 文件,我们需要将它们合并为 1 个 common.RESX 以便在它们之间共享。文件之间有些重叠,不一样,但有共同的节点。
是否有一种工具可以使用 2 个不同的 RESX 文件并创建 1 个新的合并文件,而该合并文件不会将公共元素加倍?
我不认为有这样的工具,但它很容易编写。
这是一个简单的例子:
static XDocument MergeResxFiles(string[] files)
{
var allResources =
from f in files
let doc = XDocument.Load(f)
from e in doc.Root.Elements("data")
select Resource.Parse(e, f);
var elements = new List<XElement>();
foreach (var g in allResources.GroupBy(r => r.Name))
{
elements.AddRange(MergeResources(g.Key, g));
}
var output = new XDocument(new XElement("root", elements));
return output;
}
private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
{
var grouped = resources.GroupBy(r => r.Value).ToList();
if (grouped.Count == 1)
{
yield return grouped[0].First().Xml;
}
else
{
Console.WriteLine($"Duplicate entries for {name}");
foreach (var g in grouped)
{
var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
yield return new XElement(
"data",
comments,
new XAttribute("name", name),
new XElement("value", g.Key));
}
}
}
class Resource
{
public string Name { get; }
public string Value { get; }
public string FileName { get; }
public XElement Xml { get; }
public Resource(string name, string value, string fileName, XElement xml)
{
Name = name;
Value = value;
FileName = fileName;
Xml = xml;
}
public static Resource Parse(XElement element, string fileName)
{
string name = element.Attribute("name").Value;
string value = element.Element("value").Value;
return new Resource(name, value, fileName, element);
}
}
这将使用指定文件中的资源生成一个新的 resx 文档,具有以下行为:
- 如果资源存在于多个 resx 文件中:
- 如果所有文件中的值都相同,则输出单个资源
- 否则,输出具有此名称的所有不同资源,并附上注释以指示它们来自哪些文件以帮助解决冲突。
- 否则,输出单个资源
代码将重复资源的名称打印到控制台以轻松识别它们。
例如,如果您有 2 个包含以下资源的 resx 文件:
Test
,以相同的值出现在两个文件中
Foo
,以不同的值出现在两个文件中
Bar
,仅出现在第一个文件中
Baz
,仅出现在第二个文件中
然后输出如下所示:
<root>
<data name="Test" xml:space="preserve">
<value>The value for Test</value>
</data>
<data name="Foo">
<!--Source: D:\tmp\resx\resources1.resx-->
<value>The value for Foo</value>
</data>
<data name="Foo">
<!--Source: D:\tmp\resx\resources2.resx-->
<value>Other value for Foo</value>
</data>
<data name="Bar" xml:space="preserve">
<value>The value for Bar</value>
</data>
<data name="Baz" xml:space="preserve">
<value>The value for Baz</value>
</data>
</root>
(注意:此代码未经过全面测试,可能需要一些修复和调整)
这里使用 Thomas 的代码是一个简单的控制台应用程序,它将 2 个资源文件合并到 1 个 xml 文档中。注意没有错误处理,只是一个快速工具。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace MergeResx
{
class Program
{
static void Main(string[] args)
{
var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),"resx");
var x = MergeResxFiles(new [] { Path.Combine(folder,args[0]), Path.Combine(folder, args[1])});
File.WriteAllText(Path.Combine(folder, "merged.xml"), x.ToString());
Console.WriteLine("--done--");
Console.ReadLine();
}
static XDocument MergeResxFiles(string[] files)
{
var allResources =
from f in files
let doc = XDocument.Load(f)
from e in doc.Root.Elements("data")
select Resource.Parse(e, f);
var elements = new List<XElement>();
var enumerable = allResources.GroupBy(r => r.Name).OrderBy(x=>x.Key).ToList();
foreach (var g in enumerable)
{
elements.AddRange(MergeResources(g.Key, g));
}
Console.WriteLine("Terms: " + enumerable.Count());
var output = new XDocument(new XElement("root", elements));
return output;
}
private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
{
var grouped = resources.GroupBy(r => r.Value).ToList();
if (grouped.Count == 1)
{
yield return grouped[0].First().Xml;
}
else
{
Console.WriteLine($"Duplicate entries for {name}");
foreach (var g in grouped)
{
var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
yield return new XElement(
"data",
comments,
new XAttribute("name", name),
new XElement("value", g.Key));
}
}
}
class Resource
{
public string Name { get; }
public string Value { get; }
public string Comment { get; }
public string FileName { get; }
public XElement Xml { get; }
public Resource(string name, string value, string fileName,string comment, XElement xml)
{
Name = name;
Value = value;
Comment = comment;
FileName = fileName;
Xml = xml;
}
public static Resource Parse(XElement element, string fileName)
{
string name = element.Attribute("name").Value;
string value = element.Element("value").Value;
string comment = element.Element("comment")?.Value;
return new Resource(name, value, fileName, comment, element);
}
}
}
}
我现在遇到了同样的问题。感谢之前的回复。我修改了表示的代码(增加了并行性并减少了 new
运算符的数量)以提高处理速度。
另外,现在您可以在命令行参数中设置任意数量的文件和文件夹(文件夹将搜索“.resx”文件),或者根本不指定源(文件“.resx”将在当前目录中搜索)目录)。您还可以指定结果文件的名称(默认为当前目录中的"Resources.resx")和键“-noduplicates”(如果指定此键,将不会插入重复项,遇到的第一个除外)
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace MergeResX
{
static class MergeResX
{
static void Main(string[] args)
{
var settings = args
.Select(arg => arg[0] == '-' ? ("keys", arg.TrimStart('-')) : Directory.Exists(arg) ? ("directories", arg) : File.Exists(arg) ? ("sources", arg) : ("targets", arg))
.Concat(new (string, string)[] { ("keys", null), ("directories", null), ("sources", null), ("targets", null), })
.GroupBy(item => item.Item1)
.ToDictionary(group => group.Key, group => group.Select(item => item.Item2).Where(item => !string.IsNullOrWhiteSpace(item)))
;
var files = settings["directories"].Any() || settings["sources"].Any()
? settings["directories"]
.AsParallel()
.Select(directory => new DirectoryInfo(directory))
.SelectMany(directory => directory.EnumerateFiles("*.resx", SearchOption.AllDirectories))
.Concat(settings["sources"].AsParallel().Select(source => new FileInfo(source)))
: (new DirectoryInfo(Directory.GetCurrentDirectory())).EnumerateFiles()
;
var resources = files
.AsParallel()
.Where(file => file.Length > 0)
.Select(file => XDocument.Load(file.FullName))
.SelectMany(document => document.Root.Elements("data"))
.GroupBy(element => element.Attribute("name")?.Value)
.SelectMany(group => group
.GroupBy(item => item.Attribute("value")?.Value)
.SelectMany(grouped => !grouped.Skip(1).Any() || settings["keys"].Contains("noduplicates", StringComparer.InvariantCultureIgnoreCase)
? grouped.Take(1)
: grouped.Select(item => item.WithComment("NAME DUPLICATED IN FEW RESX FILES DURING MERGE! LOOK AROUND THIS ELEMENT! BE CAREFULLY!"))))
;
new XDocument(new XElement("root", resources)).Save(settings["targets"].FirstOrDefault() ?? "Resources.resx");
}
static XElement WithComment(this XElement element, string comment)
{
element.AddFirst(new XComment(comment));
return element;
}
}
}
我们有几个来自公司几个不同项目的 RESX 文件,我们需要将它们合并为 1 个 common.RESX 以便在它们之间共享。文件之间有些重叠,不一样,但有共同的节点。
是否有一种工具可以使用 2 个不同的 RESX 文件并创建 1 个新的合并文件,而该合并文件不会将公共元素加倍?
我不认为有这样的工具,但它很容易编写。
这是一个简单的例子:
static XDocument MergeResxFiles(string[] files)
{
var allResources =
from f in files
let doc = XDocument.Load(f)
from e in doc.Root.Elements("data")
select Resource.Parse(e, f);
var elements = new List<XElement>();
foreach (var g in allResources.GroupBy(r => r.Name))
{
elements.AddRange(MergeResources(g.Key, g));
}
var output = new XDocument(new XElement("root", elements));
return output;
}
private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
{
var grouped = resources.GroupBy(r => r.Value).ToList();
if (grouped.Count == 1)
{
yield return grouped[0].First().Xml;
}
else
{
Console.WriteLine($"Duplicate entries for {name}");
foreach (var g in grouped)
{
var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
yield return new XElement(
"data",
comments,
new XAttribute("name", name),
new XElement("value", g.Key));
}
}
}
class Resource
{
public string Name { get; }
public string Value { get; }
public string FileName { get; }
public XElement Xml { get; }
public Resource(string name, string value, string fileName, XElement xml)
{
Name = name;
Value = value;
FileName = fileName;
Xml = xml;
}
public static Resource Parse(XElement element, string fileName)
{
string name = element.Attribute("name").Value;
string value = element.Element("value").Value;
return new Resource(name, value, fileName, element);
}
}
这将使用指定文件中的资源生成一个新的 resx 文档,具有以下行为:
- 如果资源存在于多个 resx 文件中:
- 如果所有文件中的值都相同,则输出单个资源
- 否则,输出具有此名称的所有不同资源,并附上注释以指示它们来自哪些文件以帮助解决冲突。
- 否则,输出单个资源
代码将重复资源的名称打印到控制台以轻松识别它们。
例如,如果您有 2 个包含以下资源的 resx 文件:
Test
,以相同的值出现在两个文件中Foo
,以不同的值出现在两个文件中Bar
,仅出现在第一个文件中Baz
,仅出现在第二个文件中
然后输出如下所示:
<root>
<data name="Test" xml:space="preserve">
<value>The value for Test</value>
</data>
<data name="Foo">
<!--Source: D:\tmp\resx\resources1.resx-->
<value>The value for Foo</value>
</data>
<data name="Foo">
<!--Source: D:\tmp\resx\resources2.resx-->
<value>Other value for Foo</value>
</data>
<data name="Bar" xml:space="preserve">
<value>The value for Bar</value>
</data>
<data name="Baz" xml:space="preserve">
<value>The value for Baz</value>
</data>
</root>
(注意:此代码未经过全面测试,可能需要一些修复和调整)
这里使用 Thomas 的代码是一个简单的控制台应用程序,它将 2 个资源文件合并到 1 个 xml 文档中。注意没有错误处理,只是一个快速工具。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace MergeResx
{
class Program
{
static void Main(string[] args)
{
var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),"resx");
var x = MergeResxFiles(new [] { Path.Combine(folder,args[0]), Path.Combine(folder, args[1])});
File.WriteAllText(Path.Combine(folder, "merged.xml"), x.ToString());
Console.WriteLine("--done--");
Console.ReadLine();
}
static XDocument MergeResxFiles(string[] files)
{
var allResources =
from f in files
let doc = XDocument.Load(f)
from e in doc.Root.Elements("data")
select Resource.Parse(e, f);
var elements = new List<XElement>();
var enumerable = allResources.GroupBy(r => r.Name).OrderBy(x=>x.Key).ToList();
foreach (var g in enumerable)
{
elements.AddRange(MergeResources(g.Key, g));
}
Console.WriteLine("Terms: " + enumerable.Count());
var output = new XDocument(new XElement("root", elements));
return output;
}
private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
{
var grouped = resources.GroupBy(r => r.Value).ToList();
if (grouped.Count == 1)
{
yield return grouped[0].First().Xml;
}
else
{
Console.WriteLine($"Duplicate entries for {name}");
foreach (var g in grouped)
{
var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
yield return new XElement(
"data",
comments,
new XAttribute("name", name),
new XElement("value", g.Key));
}
}
}
class Resource
{
public string Name { get; }
public string Value { get; }
public string Comment { get; }
public string FileName { get; }
public XElement Xml { get; }
public Resource(string name, string value, string fileName,string comment, XElement xml)
{
Name = name;
Value = value;
Comment = comment;
FileName = fileName;
Xml = xml;
}
public static Resource Parse(XElement element, string fileName)
{
string name = element.Attribute("name").Value;
string value = element.Element("value").Value;
string comment = element.Element("comment")?.Value;
return new Resource(name, value, fileName, comment, element);
}
}
}
}
我现在遇到了同样的问题。感谢之前的回复。我修改了表示的代码(增加了并行性并减少了 new
运算符的数量)以提高处理速度。
另外,现在您可以在命令行参数中设置任意数量的文件和文件夹(文件夹将搜索“.resx”文件),或者根本不指定源(文件“.resx”将在当前目录中搜索)目录)。您还可以指定结果文件的名称(默认为当前目录中的"Resources.resx")和键“-noduplicates”(如果指定此键,将不会插入重复项,遇到的第一个除外)
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace MergeResX
{
static class MergeResX
{
static void Main(string[] args)
{
var settings = args
.Select(arg => arg[0] == '-' ? ("keys", arg.TrimStart('-')) : Directory.Exists(arg) ? ("directories", arg) : File.Exists(arg) ? ("sources", arg) : ("targets", arg))
.Concat(new (string, string)[] { ("keys", null), ("directories", null), ("sources", null), ("targets", null), })
.GroupBy(item => item.Item1)
.ToDictionary(group => group.Key, group => group.Select(item => item.Item2).Where(item => !string.IsNullOrWhiteSpace(item)))
;
var files = settings["directories"].Any() || settings["sources"].Any()
? settings["directories"]
.AsParallel()
.Select(directory => new DirectoryInfo(directory))
.SelectMany(directory => directory.EnumerateFiles("*.resx", SearchOption.AllDirectories))
.Concat(settings["sources"].AsParallel().Select(source => new FileInfo(source)))
: (new DirectoryInfo(Directory.GetCurrentDirectory())).EnumerateFiles()
;
var resources = files
.AsParallel()
.Where(file => file.Length > 0)
.Select(file => XDocument.Load(file.FullName))
.SelectMany(document => document.Root.Elements("data"))
.GroupBy(element => element.Attribute("name")?.Value)
.SelectMany(group => group
.GroupBy(item => item.Attribute("value")?.Value)
.SelectMany(grouped => !grouped.Skip(1).Any() || settings["keys"].Contains("noduplicates", StringComparer.InvariantCultureIgnoreCase)
? grouped.Take(1)
: grouped.Select(item => item.WithComment("NAME DUPLICATED IN FEW RESX FILES DURING MERGE! LOOK AROUND THIS ELEMENT! BE CAREFULLY!"))))
;
new XDocument(new XElement("root", resources)).Save(settings["targets"].FirstOrDefault() ?? "Resources.resx");
}
static XElement WithComment(this XElement element, string comment)
{
element.AddFirst(new XComment(comment));
return element;
}
}
}