【问题标题】:Consolidate 2 different RESX files - Windows ASP.NET合并 2 个不同的 RESX 文件 - Windows ASP.NET
【发布时间】:2015-08-03 23:58:09
【问题描述】:

我们有来自公司几个不同项目的几个 RESX 文件,我们需要将它们合并为 1 个 common.RESX 以便在它们之间共享。文件之间有一些重叠,它们不一样,但有共同的节点。

是否有一种工具可以获取 2 个不同的 RESX 文件并创建 1 个新的组合,该组合不会将公共元素加倍?

【问题讨论】:

  • Resx 文件的名称是否相同?您需要担心的不仅仅是元素名称冲突。所有使用通用 RESX 的应用程序都必须适应使用通用文件。

标签: c# asp.net visual-studio 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 文件中:
    • 如果所有文件的值都相同,则输出单个资源
    • 否则,使用此名称输出所有不同的资源,并使用 cmets 指示它们来自哪些文件以帮助解决冲突。
  • 否则,输出单个资源

代码将重复资源的名称打印到控制台以轻松识别它们。

例如,如果您有 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>

(注意:此代码未经彻底测试,可能需要一些修复和调整)

【讨论】:

    【解决方案2】:

    这里使用 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);
            }
        }
    }
    

    }

    【讨论】:

      【解决方案3】:

      我现在也有同样的问题。感谢之前的回复。我修改了表示的代码(添加了并行性并减少了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;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-20
        • 1970-01-01
        • 2015-05-18
        • 2014-08-13
        • 2019-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多