We have several RESX files from several different projects in the company that we need to consolidate into 1 common.RESX to share among them all. There is some overlap between the files, they are not the same, but there are common nodes.
Is there a tool which can take 2 different RESX files and create 1 new combines one which doesn't double up common elements?
I don't think there is such a tool, but it is pretty easy to write.
Here's a quick example:
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);
}
}
This will generate a new resx document with the resources from the specified files, with the following behavior:
The code prints the names of duplicate resources to the console to identify them easily.
For instance, if you have 2 resx files with the following resources:
Test
, present in both files with the same valueFoo
, present in both files with different valuesBar
, present only in the first fileBaz
, present only in the second fileThen the output looks like this:
<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>
(note: this code wasn't thoroughly tested, and might need some fixes and adjustments)