Pocket PC 的国际化猜字游戏






4.03/5 (15投票s)
随着全球化进程的加快,国际化应用程序变得越来越重要。这个猜词游戏是 .NET Compact Framework 国际化功能的一个有趣入门。
配置为加泰罗尼亚语的 Pocket PC 上的猜词游戏
引言
本文是对 .NET Compact Framework 国际化(或者应该说是国际化)功能的基本介绍。 .NET Compact Framework 就像它的“大哥”一样,拥有丰富的特性,可以帮助开发人员为多个地区编写应用程序。其中很多支持都是自动实现的,这大大简化了开发。然而,有些事情需要提前考虑,才能为您的应用程序提供国际化支持。
为了演示这些功能,我将代码围绕一个猜词游戏构建,我希望即使您对国际化不感兴趣,也会觉得它本身很有趣和吸引人。最终的游戏有英语、法语、加泰罗尼亚语和西班牙语版本。有趣的是,这些也是欧洲在使用本初子午线的主要语言。
背景
国际化应用程序(也称为全球化应用程序)是指能够处理国际数据的应用程序。具体的翻译称为“本地化”。
猜词游戏实现
猜词游戏有一个 LocaleManager
类,用于管理资源,这意味着游戏可以在运行时更改语言。该类的静态初始化器将当前区域设置为与当前 UI 区域相同,这样至少游戏会以 Pocket PC 的区域设置中指定的语言启动(当然,前提是游戏在该语言中有资源)。
static LocaleManager()
{
_current = CultureInfo.CurrentUICulture;
Assembly asm = Assembly.GetExecutingAssembly();
_resMan = new ResourceManager("Hangman.hmlocal", asm);
}
在游戏过程中,任何时候使用将输出给用户的字符串,文本都将通过 LocalManager.GetString(string id)
方法从正确的资源集中检索。
public static string GetString(string id)
{
return _resMan.GetString(id, _current);
}
您可以看到这是一个非常简单的方法,它只检索带有给定标识符(稍后会介绍)的字符串,并为在静态初始化器中检索到的当前区域设置。如果指定的区域设置不可用,则框架将使用回退区域设置作为后备,这样至少会有一些可用的内容。下图说明了 .NET 中区域信息(源自 RFC 1766)的组织结构([^])。
稍后我将介绍这如何转化为应用程序。层次图顶部的绿色层是回退。如果系统无法匹配任何其他区域设置,则将使用此设置。第二层,带有水绿色背景,是主语言标记。这一层不定义诸如特定于区域设置的日期格式(想想英国英语和美国英语之间的区别 - 1/2/03 可以是 2 月 1 日或 1 月 2 日,或者在使用逗号 [在欧洲大陆] 或句点 [在英语国家] 作为数字的小数分隔符)。最后,第三层,带有黄色背景,添加了第一个子标签,实际上添加了区域代码。区域代码有助于定义日期和数字格式等内容。
验证用户输入
为了游戏的需要,用户可以输入任何字母,然而同一个字母可能有几种表示方式。传统上,在英语国家,这种类型的比较是通过将字母大小写设置为相同然后进行比较来教授的。例如:
if (myStringA.ToLower() == myStringB.ToLower()) {/*do something*/}
当然,这就是我在大学里学到的,而且我没有看到太多这方面变化的证据。
在更国际化的背景下,例如,字母“a”可以写成大写“A”,带尖音符“á”,重音符“à”,抑扬符“â”,波浪符“ã”,分音符“ä”(有时也称为元音分离号),上方加圆圈的“å”等等(我们甚至不讨论长音符、短音符、鼻音符以及所有其他修饰符及其大写形式,对这样一个简单的字母)。
可以将字母“a”与所有这些变体进行比较,但 myChar.ToLower()
在这种情况下是不够的。需要将字符转换为字符串,然后可以使用 InvariantCulture
比较这两个字符串。游戏中的 LocaleManager
类实现如下:
public static bool IsEqual(char a, char b)
{
// The Compare method doesn't have char overloads so convert
// the characters in to a string
string sa = StringInfo.GetNextTextElement(new string(a,1));
string sb = StringInfo.GetNextTextElement(new string(b,1));
// Perform a culture neutral comparison
int res = CultureInfo.InvariantCulture.CompareInfo.Compare(sa, sb,
CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
// If the comparison yielded a result of zero, then char a and b
// are equal (disregarding case and accent)
return res == 0;
}
本地化资源
在 Visual Studio 中,最简单的做法之一是为支持的每种语言(和区域)创建一个 resx 文件。这些文件在解决方案构建时会被转换为附属程序集。resx 文件就是一个包含本地化字符串的 XML 文件。在演示游戏中,资源文件的回退名称是“hmlocal”,要添加额外的区域设置,只需创建一个 resx 文件,格式为 fallback.language[-region].resx(区域部分是可选的)。
尽管演示应用程序没有显示这一点,但 resx 文件不一定只包含字符串,它们还可以包含任何任意对象,如图形、音频或您可以想到的任何其他内容。
例如(hmlocal.resx 的一部分)
<data name="play_timed_intro">
<value>You have {0} seconds to guess the word or phrase!</value>
</data>
<data name="play_intro">
<value>You have to guess the word or phrase!</value>
</data>
<data name="play_hurry">
<value>Hurry! You have {0} second left!</value>
</data>
以及它来自 hmlocal.ca.resx 的加泰罗尼亚语版本
<data name="play_timed_intro">
<value>Tens {0} segons per endivinar la paraula o frase!</value>
</data>
<data name="play_intro">
<value>Has d'endivinar la paraula o frase!</value>
</data>
<data name="play_hurry">
<value>Vinga! Et queden nomes {0} segons!</value>
</data>
附属程序集相对于主程序集的目录结构
项目构建时,Visual Studio 会将所有本地化资源放入附属程序集中。回退资源放在主程序集中,而特定区域的程序集则在主程序集正下方的适当子文件夹中创建。
CF 与完整 .NET Framework 之间的区别
在完整的 .NET Framework 中,可以在 CurrentThread
上设置 CurrentCulture
,这反过来会更改应用程序的默认区域设置。然而,这在 Compact .NET Framework 中不可用。在正常情况下,应用程序不太可能需要这样做,因此不支持。
关注点
如果您对“选项”卡和“游戏”菜单页面为什么会引用“玩家 1”,而实际上只能有一个玩家,是因为我在未来某个时候打算扩展游戏,允许一个两人模式,玩家可以通过(IR 或蓝牙)相互传达单词。
参考资料和资源
如果您想了解更多关于本地化和全球化的信息,那么以下链接可能会对您有所帮助。
感谢
感谢我的好朋友,也是 CodeProject 的同事 David Llamas[^],他进行了加泰罗尼亚语翻译,并纠正了我西班牙语翻译(显然,我使用了老式的、祖母会用的词)。还要感谢 Jeannette,她是我母亲的朋友,她进行了法语翻译,尽管她以前从未用过电脑。
历史
这是 1.0 版本。