.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-ES
和 Strings
文件在该特定文化中也是如此 - 如果用户使用其他东西,例如 es-UY
,他会从 .NET 获得 es-ES
的回退,但这对我们的计算不起作用。我可以将 GetResourceSet()
中的 tryParents
布尔值切换为 true
,但是我总是会在原始 Strings
文件中声明的 en-US
字符串上得到一个回退形式,所以我们总是有 100% 的翻译进度,即使用户选择了完全不同的文化。
所以基本上,根据我们在 Strings.resx
中的 10 个资源和 Strings.es-ES.resx
中的 6 个资源的示例,应该会发生以下情况:
- 我们在使用
en-US
文化时获得 100% 的完成度。
- 我们在使用
en-GB
文化时获得 100% 的完成度,因为它回落到 en-US
,我们已经涵盖了那个。
- 我们在使用
es-ES
文化时获得 60% 的完成度。
- 我们在使用
es-UY
文化时完成了 60%,因为 .NET 认为 es
,然后 es-ES
作为后备。请注意,我们没有 es
,但声明了 es-ES
。
- 我们在使用
zh-CN
时获得 0% 的完成度,即使最深的回退是我们已经涵盖的 en-US
。
我想以最好的方式解决这个问题,但我不太确定 是什么 最好的方式 - 我认为简单地获取资源数量就可以了,它确实如此,但不是方言,并且尝试所有 parents 也不起作用,因为它总是导致 en-US
。另一方面,我想假设任何比 Strings.resx
更好的回退都可以被认为是翻译的,因为 es-ES
对于 es-UY
用户来说完全没问题,但是 en-US
对 zh-CN
不利。另一方面,en-US
对 en-GB
用户来说完全没问题。
也许我可以通过某种方式比较 ResourceSet
和 tryParents
集并比较哪些字符串不同?不过,它需要进行参考比较,因为某些字符串完全有可能在两种不同的语言中具有相同的翻译。有可能吗?
欢迎提出任何建议。
关于这个问题,这是我想出的最好的办法:
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);
}
它只需要两个相当不错的假设:
- 当前文化资源集的资源不能超过我们的默认 (en-US) 文化,仅进行翻译时总是如此。
- 如果我们 100% 完成翻译,我们必须至少有 1 个翻译资源与原始默认字符串具有不同的表示形式,否则无法判断这是预期的翻译资源集,还是从中提取的默认资源zh-CN.
我对这个解决方案非常满意。
从标题可能有点难以猜到我的意思,所以让我详细说明一下。
我有一个使用资源 (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-ES
和 Strings
文件在该特定文化中也是如此 - 如果用户使用其他东西,例如 es-UY
,他会从 .NET 获得 es-ES
的回退,但这对我们的计算不起作用。我可以将 GetResourceSet()
中的 tryParents
布尔值切换为 true
,但是我总是会在原始 Strings
文件中声明的 en-US
字符串上得到一个回退形式,所以我们总是有 100% 的翻译进度,即使用户选择了完全不同的文化。
所以基本上,根据我们在 Strings.resx
中的 10 个资源和 Strings.es-ES.resx
中的 6 个资源的示例,应该会发生以下情况:
- 我们在使用
en-US
文化时获得 100% 的完成度。 - 我们在使用
en-GB
文化时获得 100% 的完成度,因为它回落到en-US
,我们已经涵盖了那个。 - 我们在使用
es-ES
文化时获得 60% 的完成度。 - 我们在使用
es-UY
文化时完成了 60%,因为 .NET 认为es
,然后es-ES
作为后备。请注意,我们没有es
,但声明了es-ES
。 - 我们在使用
zh-CN
时获得 0% 的完成度,即使最深的回退是我们已经涵盖的en-US
。
我想以最好的方式解决这个问题,但我不太确定 是什么 最好的方式 - 我认为简单地获取资源数量就可以了,它确实如此,但不是方言,并且尝试所有 parents 也不起作用,因为它总是导致 en-US
。另一方面,我想假设任何比 Strings.resx
更好的回退都可以被认为是翻译的,因为 es-ES
对于 es-UY
用户来说完全没问题,但是 en-US
对 zh-CN
不利。另一方面,en-US
对 en-GB
用户来说完全没问题。
也许我可以通过某种方式比较 ResourceSet
和 tryParents
集并比较哪些字符串不同?不过,它需要进行参考比较,因为某些字符串完全有可能在两种不同的语言中具有相同的翻译。有可能吗?
欢迎提出任何建议。
关于这个问题,这是我想出的最好的办法:
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);
}
它只需要两个相当不错的假设:
- 当前文化资源集的资源不能超过我们的默认 (en-US) 文化,仅进行翻译时总是如此。
- 如果我们 100% 完成翻译,我们必须至少有 1 个翻译资源与原始默认字符串具有不同的表示形式,否则无法判断这是预期的翻译资源集,还是从中提取的默认资源zh-CN.
我对这个解决方案非常满意。