【转】Delphi 开发跨平台 Android / iOS 程序的多语言

使用 Delphi 的 FireMonkey 框架,开发跨平台的程序,可以做到一个源码,编译成 Windows, Mac OS, Android, iOS,甚至是 Linux 上面运行的程序。

简单说,就是可以开发 Android 和 iOS 的 APP,同时代码不修改也可以运行在 Windows 上和 Mac OS 上面。

如果你发布的 APP 需要给各国用户使用,需要考虑多语言的支持。我之前有博客文章写过如何实现多语言支持:

假期有时间写代码:FireMonkey 之多语言(TLang)

问题简述

数据库的中文内容,在手机系统语言非中文时,显示乱码。此现象出现在 Android 和 iOS 上面。Windows 上面没有此问题。

一些使用多语言框架需要注意的细节

1. 设计期,一个 TLabel 或者其它控件,只要它有 AutoTranslate 属性,将这个属性设置为 True,拿 TLabel 作为例子,在设计期设置好它的 Text 属性为特定的字符串,比如【温度】,然后在语言前述文章里面提到的语言文件里面有【温度=Temperature】这样的翻译内容,则程序运行时,切换了语言,则 TLabel 的 Text 显示的文字内,自动变化为 Temperature 这个翻译后的文字。

2. 运行期:假设运行期,在一个 Button1.OnClick 事件里面,有代码:

Label1.Text := '温度';
则它仍然显示汉字的温度,不会自动变成英文,即便当前的语言设置是英文。

这里有两种办法解决这个问题。

2.1. 办法一:赋值语句,调用翻译函数,将翻译后的字符串赋值给 Label1,代码:

Label1.Text := Translate('温度');
这个办法,前述文章提到过。

2.2. 办法二:触发自动翻译,代码:

Label1.Text := '温度';
TStyleManager.UpdateScenes; //---- 执行这行代码,Label1.Text 会自动翻译。前提是设置 Label1.AutoTranslate 属性为 True;

//---- TStyleManager.UpdateScenes; 这个方法需要 uses Fmx.Styles 单元。

一个更大的问题:数据库内容的多语言显示

在 FireMonkey 框架底下,我们可以使用 SQLite 数据库作为 APP 程序的本地数据库,将其内容显示呈现在界面上。

假设数据库里面有个表,里面有一些设计期就写入的内容,在用户使用 APP 时,这些内容会显示在 APP 界面上。同时我们希望用户使用不同语言的时候,同样的内容,要显示为对应的语言。

数据库的内容要显示到界面,这里可以采用 Delphi 提供的 LiveBindings 方法,将界面上的 ListView 或者 Label 等控件绑定到数据库指定的字段上。

数据库游标滚动后显示的内容

当数据库的游标滚动,在使用 LiveBindings 技术的情况下,Label 显示的内容自动跟随显示当前 DataSet 的游标所在记录的对应字段的内容,这时候,显示的是数据库里面的原始的字段内容字符串,并不是我们希望的当前用户设置的语言对应的文字。这里其实就是相当于运行期在为 Label1.Text 赋值。此时,在数据库游标滚动后,需要增加一行代码:TStyleManager.UpdateScenes; 让多语言框架触发自动翻译,然后用户看到的就是对数据库的内容翻译后的内容。

数据库内容在不同语言的系统里面显示乱码,自动翻译失败

在 FireMonkey 里面,数据库控件,我喜欢使用 FireDAC 那套。

如果字符串字段的类型是 TStringField,里面的内容是中文值,则:

1. 在 Windows 底下,无论系统语言是中文还是英文,都没有问题;

2. 在 Android 和 iOS 底下,系统语言是中文没有问题;系统语言是英文,则显示出来的文字是乱码,当然也就会翻译失败。因为我们的翻译内容是【温度=Temperature】,是乱码,而不是【温度】,使得自动翻译找不到对应的 Key 值,在找不到语言文件里面的对应的 Key 值得情况下,自动翻译将给出没翻译的原始内容,而这个内容是乱码。因此,显示乱码。

解决这个问题:字段类型为 TWideStringField,则上述问题解决。

假设本地数据库采用 SQLite,要怎样做才能让 TFdQuery 这个 DataSet 的字段类型是 TWideStringFied ?

在 SQLite 数据库里面,设计的时候,存储字符串的字段,如果类型是 VarChar 则对应该字段的 Delphi 的 DataSet 里面的字段类型是 TStringField;

如果 SQLite 的字段类型是 NVarChar 字段,则 Delphi 里面对应的字段类型是 TWideStringField;

因此,如果数据库的内容想要在多种系统语言下面正确显示,简单说,要在英文为系统语言的手机上,正确显示数据库内容而不是显示乱码,使用 SQLite 作为手机端本地数据库来使用的话,SQLite 的字段类型应该是 NVarChar 而不是 VarChar。

做到上述几点,数据库内容是中文,也能正确将中文显示在英文系统语言的手机上。

但是,如果数据库内容是中文,在英文系统语言的手机上想要显示为翻译后的英文,那么,就需要在运行期,在数据库滚动后(DataSet.Next 或类似的操作),调用一次 TStyleManager.UpdateScenes;

当然,重复一下:想要自动翻译,前提是使用 LoadLangFromStrings 函数事先加载对应的翻译词条。

总结:

1. 使用 LoadLangFromStrings 加载对应语言的 Key=Value 的翻译词条;

2. SQLite 的字段使用 NVarChar 而不是 VarChar 类型,对应的 Delphi 的 DataSet 里面的字段类型是 TWideStringField 而不是 TStringField;

3. 运行期改变的界面元素的内容后,比如使用 LiveBindings 绑定 TLabel.Text 到数据库的 DataSet 的某个字段,当 DataSet 滚动后,调用一次 TStyleManager.UpdateScenes; 触发自动翻译。

 

原文地