.NET 中覆盖 culture-specific 资源的可靠计算

Reliable calculation of overriden culture-specific resources in .NET

从标题可能有点难以猜到我的意思,所以让我详细说明一下。

我有一个使用资源 (resx) 进行翻译的应用程序。我有包含所有字符串的标准 Strings.resx 文件,以及在特定 xx-XX 文化中覆盖它们的 Strings.xx-XX.resx 文件。初始 Strings.resx 文件有 X 个字符串,其中 culture-specific Strings.xx-XX.resx 文件可能少于或等于 X 个字符串。

我正在尝试编写一个函数,该函数能够可靠地计算有多少字符串在该语言中被覆盖,与初始数字相比可以给我一个不错的整体翻译百分比。

例如,我们总共有 10 个字符串,es-ES 文化中有 6 个字符串。当 es-ES 用户启动应用程序时,他会收到一条消息,提示 es-ES 翻译在 60% 内完成。

到目前为止,我设法编写了如下代码:

ushort defaultResourceSetCount = 0;
ResourceSet defaultResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-US"), true, true);
if (defaultResourceSet != null) {
    defaultResourceSetCount = (ushort) defaultResourceSet.Cast<object>().Count();
}

ushort currentResourceSetCount = 0;
ResourceSet currentResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, false);
if (currentResourceSet != null) {
    currentResourceSetCount = (ushort) currentResourceSet.Cast<object>().Count();
}

if (currentResourceSetCount < defaultResourceSetCount) {
    // This is our percentage that we want to calculate and show to user
    float translationCompleteness = currentResourceSetCount / (float) defaultResourceSetCount;
}

以上代码有效,但有很多我想解决的方言限制。它基本上只适用于具有特定文化的非常普遍的情况,例如 es-ESStrings 文件在该特定文化中也是如此 - 如果用户使用其他东西,例如 es-UY,他会从 .NET 获得 es-ES 的回退,但这对我们的计算不起作用。我可以将 GetResourceSet() 中的 tryParents 布尔值切换为 true,但是我总是会在原始 Strings 文件中声明的 en-US 字符串上得到一个回退形式,所以我们总是有 100% 的翻译进度,即使用户选择了完全不同的文化。

所以基本上,根据我们在 Strings.resx 中的 10 个资源和 Strings.es-ES.resx 中的 6 个资源的示例,应该会发生以下情况:

我想以最好的方式解决这个问题,但我不太确定 是什么 最好的方式 - 我认为简单地获取资源数量就可以了,它确实如此,但不是方言,并且尝试所有 parents 也不起作用,因为它总是导致 en-US。另一方面,我想假设任何比 Strings.resx 更好的回退都可以被认为是翻译的,因为 es-ES 对于 es-UY 用户来说完全没问题,但是 en-USzh-CN 不利。另一方面,en-USen-GB 用户来说完全没问题。

也许我可以通过某种方式比较 ResourceSettryParents 集并比较哪些字符串不同?不过,它需要进行参考比较,因为某些字符串完全有可能在两种不同的语言中具有相同的翻译。有可能吗?

欢迎提出任何建议。

关于这个问题,这是我想出的最好的办法:

if (CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("en")) {
    return;
}

ResourceSet defaultResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-US"), true, true);
if (defaultResourceSet == null) {
    return;
}

HashSet<DictionaryEntry> defaultStringObjects = new HashSet<DictionaryEntry>(defaultResourceSet.Cast<DictionaryEntry>());
if (defaultStringObjects.Count == 0) {
    return;
}

ResourceSet currentResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
if (currentResourceSet == null) {
    return;
}

HashSet<DictionaryEntry> currentStringObjects = new HashSet<DictionaryEntry>(currentResourceSet.Cast<DictionaryEntry>());
if (currentStringObjects.Count >= defaultStringObjects.Count) {
    // Either we have 100% finished translation, or we're missing it entirely and using en-US
    HashSet<DictionaryEntry> testStringObjects = new HashSet<DictionaryEntry>(currentStringObjects);
    testStringObjects.ExceptWith(defaultStringObjects);

    // If we got 0 as final result, this is the missing language
    // Otherwise it's just a small amount of strings that happen to be the same
    if (testStringObjects.Count == 0) {
        currentStringObjects = testStringObjects;
    }
}

if (currentStringObjects.Count < defaultStringObjects.Count) {
    float translationCompleteness = currentStringObjects.Count / (float) defaultStringObjects.Count;
    Console.WriteLine("Do something with translation completeness: " + translationCompleteness);
}

它只需要两个相当不错的假设:

  1. 当前文化资源集的资源不能超过我们的默认 (en-US) 文化,仅进行翻译时总是如此。
  2. 如果我们 100% 完成翻译,我们必须至少有 1 个翻译资源与原始默认字符串具有不同的表示形式,否则无法判断这是预期的翻译资源集,还是从中提取的默认资源zh-CN.

我对这个解决方案非常满意。