使用 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; 觸發自動翻譯。
原文地址
