Search code examples
c#asp.netvisual-studioresx

Consolidate 2 different RESX files - Windows ASP.NET


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?


Solution

  • 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:

    • if a resource exists in several resx files:
      • if the value is the same in all files, output a single resource
      • else, output all different resources with this name, with comments indicating which files they came from to help resolve conflicts.
    • else, output the single resource

    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 value
    • Foo, present in both files with different values
    • Bar, present only in the first file
    • Baz, present only in the second file

    Then 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)