程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在 Java 開發過程中支持雙向字符集語言(BiDi)

在 Java 開發過程中支持雙向字符集語言(BiDi)

編輯:關於JAVA

BiDi 是什麼

W3C 對雙向字符集語言(即 BiDi)進行了如下的定義:

雙向字符集語言通常是指文字可以從左到右(LTR)和從右到左(RTL)雙向書寫的文字。 例如,阿拉伯和希伯來語言的文字書寫通常是從右到左,但是其中的其它字符集(例如拉丁 文字)依然保持從左到右的格式。當然其它的語言文字,例如英文,如果包含阿拉伯或者希 伯來文字摘要的話,也可以是雙向書寫的。通常將主方向稱為全局方向。

對於介紹一種的新的知識或者技術,筆者通常習慣於從“what、 why、who、how”幾個方 面來進行講述。即 BiDi 是什麼,這在本節中作了介紹。為什麼需要支持 BiDi,這會在下一 節中介紹。隨後則偏重於介紹作為一名 Java 軟件開發人員在支持 BiDi 的時候要考慮哪些 問題,如何做才能實現 BiDi 支持,以及一些常見的問題和解決技巧。

為什麼需要 BiDi 支持

對於使用雙向字符集地區的人來說,對於本國文字和其它字符集文字,例如和英語混排的 情況,在紙面上書寫將是一件需要有規劃技巧的事情。如下所示:

CIBARA english CIBARA

CIBARA 代表阿拉伯字符,english 代表英語字符。書寫者需要從右到左書寫字符“A”“ R”“A”“B”“I”“C”,在紙面就變成 CIBARA。隨後要書寫英文字符 english,這段字 符要從左到右顯示,這就需要書寫者要先規劃合適的空白來書寫文字,然後繼續下面的阿拉 伯字符的顯示。否則要麼空間不夠,寫不下那麼多文字,要麼留下一段空白影響文檔的整體 結構。

計算機的出現對雙向字符集的錄入應該是一大福音,上面所述的空白規劃將不再是問題。 當計算機切換到 BiDi 文字的錄入方式後,對於一般的雙向字符集字符,例如阿拉伯文字, 顯示將遵循全局方向從右到左(RTL)。當需要輸入英文字符的時候,計算機將自動處理英文 字符的顯示,將先輸入的字符自動向左邊排,後輸入的字符顯示在前面字符的右側,將先輸 入的文字頂到了左側,而錄入光標將一直停留在英文錄入的最右側,依次處理隨後的文字錄 入,並顯示。這樣錄入者就不用關心這段英文文字將占據多大空間,而且英文內容保持了從 左到右(LTR)的方向。當用戶需要輸入阿拉伯文字的時候,阿拉伯字符將自動放置到英文內 容的左側,錄入光標也跟隨到了阿拉伯字符的左側,開始正常的從右到左(RTL)的錄入,並 顯示。

計算機軟件要在使用雙向字符集的地區(主要是中東地區)銷售、使用,如果沒有 BiDi 的支持,將是一件不可能的事情。對 BiDi 的支持也是軟件國際化(globalization)標准重 要的組成部分,沒有 BiDi 的支持就不能說對軟件實現了國際化的支持。世界上各大軟件公 司都把對 BiDi 的支持作為產品能否發布的一個重要考核指標。

事實上對 BiDi 的支持,要考慮的內容非常多,從底層 BiDi 算法(例如 ICU4J)、編碼 (Unicode)、存儲、輸入法、直至開發工具的支持。然而作為一名開發人員(本文主要針對 Java 開發人員),其實不需要了解太多底層實現的細節。針對不同的軟件圖形庫,只需要很 少的代碼層面的處理就可以實現對 BiDi 的支持。如果讀者想要了解更多 BiDi 層面的知識 、術語,例如 logical order、visual order 等等可以參照 developeWorkss 或者 W3C 上 的其它文章。

Java 1.5 對 BiDi 的支持

Java SDK 不同的版本對 BiDi 的支持能力也是不一樣的。本文的示例以及代碼片段主要 是針對 JDK 1.5 的版本。

Java 提供了 AWT 和 Swing 兩種圖形庫,這兩種圖形庫對 BiDi 的支持是不一樣的。軟 件對 BiDi 展示層面的支持包含整個軟件界面的布局從 LTR 到 RTL 的轉變,以及控件的布 局。例如 ComboBox 的下拉箭頭從左邊移到右邊,控件裡面的文字的布局轉換,文字的錄入 等等。

AWT

AWT(Abstract Windowing Toolkit),中文譯為抽象窗口工具包,是 Java 提供的用來 構建和設置 Java 圖形用戶界面的基本工具。這個工具包提供了一套與本地圖形界面進行交 互的接口。AWT 中的圖形函數與操作系統所提供的圖形函數之間有著一一對應的關系。當我 們利用 AWT 來構件圖形用戶界面的時候,實際上是在利用操作系統所提供的圖形庫。對於 BiDi 來講,AWT 組件裡面的文字布局實際上依賴於底層操作系統。另外,AWT 組件對 BiDi 要求的控件布局也有諸多缺陷,因此 Java 軟件開發人員如果要開發支持 BiDi 的應用程序 ,就不要采用 AWT。

Swing

Swing 是一個用於開發 Java 應用程序用戶界面的開發工具包。它是 Sun 與 Netscape 合作建立的一個高級圖形庫。與 AWT 相比,Swing 具有更豐富而且更加方便的用戶界面元素 集合,Swing 對於底層平台的依賴更少。因此,Swing 可以在不同平台上提供給用戶統一的 視覺體驗。

在 BiDi 支持方面,因為 Swing 組件是純 Java 編寫,所以 Swing 的 BiDi 支持可以完 全獨立於底層的操作系統。

Java 最重要的 BiDi 相關類是 java.awt.ComponentOrientation,這個類提供了幾個基 本方法和常量來設置 Java 應用程序的全局方向。

ComponentOrientation. getOrientation (Locale  locale)
返回指定 Locale 的全局方向

ComponentOrientation. isLeftToRight ()
判斷當前的應用程序是否是從左到右的方向

ComponentOrientation 還提供了常量 LEFT_TO_RIGHT,RIGHT_TO_LEFT 來指定全局方向 的取值。

另外一個 componentOrientation 類的使用密切相關的方法就是 Component. applyComponentOrientation (ComponentOrientation  o)

這個方法可以設置 java.awt.Component 對象以及所有它所包含的子對象的全局方向。

下面的示例代碼演示了如何打開 Swing 對 BiDi 的基本支持,並根據系統的區域設置來 決定應用程序的全局方向。

public class BiDiApp extends JFrame {
   ...
   public static void main(String[] args) {
     ...
     new BiDiApp ();
     ...
   }

   public BiDiApp () {
     ...
     super();
     ...
     applyComponentOrientation(ComponentOrientation
       .getOrientation(Locale.getDefault()));
     ...
   }
  }

通過方法 applyComponentOrientation,Swing 控件以及其包含的子控件的 BiDi 設置, 都可以根據計算機當前的區域設置來自動調整。如上一段代碼所示,如果計算機當前的區域 是在英語區域,則應用程序啟動以後,按照正常的英語應用程序顯示和處理文字。如果計算 機當前的區域是在雙向字符集區域,程序啟動以後,程序的 UI 布局 、控件的文字方向,以 及錄入光標的位置等等就會變成 BiDi 地區的使用方式。

圖 1. 應用程序 BiDi 示例

注:顯示非英文字符需要相應的文字資源以及相應的國際化支持,這些不在本文的介紹范 圍之內,讀者請參閱其它資料查看這方面的內容。

雖然通過上面的方法可以打開對 BiDi 的支持,但是 Swing 中的一些控件對 BiDi 的支 持是有缺陷的,這需要開發人員做一些額外的處理才能完整地支持 BiDi。下面筆者將一一介 紹這些有 BiDi 支持缺陷的 Swing 控件以及其對應的解決辦法。

JFrame

在應用了 applyComponentOrientation 以後,JFrame 控件的標題欄如圖 1 所示,是沒 有翻轉成為從右到左 RTL 方向的。開發人員可以采用下面這段示例程序來使 JFrame 的標題 欄變為從右到左 RTL 方向。

if (!ComponentOrientation.getOrientation(Locale.getDefault ()).isLeftToRight()) {
   JFrame.setDefaultLookAndFeelDecorated(true);
}

應用這段代碼以後,圖 1 的應用程序標題欄將會變成如圖 2 所示:

圖 2. JFrame 標題欄從右到左顯示

需要指出的是,應用這段代碼以後,JFrame 的外觀將不再遵循操作系統界面風格。用戶 需要自己決定是否采用這段代碼來實現 JFrame 標題欄的 RTL,還是保持界面整體的風格不 變。

javax.swing.Box

javax.swing.Box 是一個輕量級的,可以放置各種簡單控件(例如 JButton)的容器。使 用 Box 可以比較方便地控制其中控件的布局。然而,使用 Box 也帶來了 BiDi 上面的一個 缺憾,applyComponentOrientation 設置的全局方向不能應用到 Box 裡面包含的各個控件上 。

圖 3. Box BiDi 從左到右顯示

為了使 Box 裡面的控件布局符合 ComponentOrientation 的取值,開發人員必須通過如 下示例代碼來生成 Box 的實例對象。

Box box = new Box(BoxLayout.LINE_AXIS);

//將控件加入到 box 對象中

box.add(Btn1); //Btn1,instance of JButton

box.add(Btn2); //Btn2,instance of JButton

這樣 Box 裡面包含的控件將遵循這個應用程序的全局方向,如下圖所示:

圖 4. Box BiDi 從右到左顯示

javax.swing.JComboBox

即便 ComponentOrientation 應用了從右到左 RTL 的全局方向,javax.swing.JComboBox 控件裡面的文字缺省還是按照左對齊的方式顯示。如下圖所示:

圖 5. JComboBox 內的文字左對齊

開發人員可以調用如下代碼生成 JComboBox 的實例對象,強制 JComboBox 對象的文字遵 循右對齊的方向。如圖 6 所示:

JComboBox box = new JComboBox();

//align all the comboBox items to RTL in case Arabic/Hebrew  locale
if (!ComponentOrientation.getOrientation(Locale.getDefault ()).isLeftToRight()) {
   ((JLabel)box.getRenderer()).setHorizontalAlignment (SwingConstants.RIGHT);
}

圖 6. JComboBox 內的文字右對齊

javax.swing.JTable

javax.swing.JTable 的表格裡面的內容在缺省情況下也不會按照 ComponentOrientation 取值進行顯示。即便 ComponentOrientation 是從右到左 RTL,JTable 還是會如下圖所示顯 示內容:

圖 7. JTable 內的文字左對齊

開發人員可以調用如下代碼生成 JTable 的實例對象,強制 JTable 對象裡面的文字遵循 右對齊的方向。如圖 8 所示

JTable table= new JTable(...);
//align all the table column data to RTL in case Arabic/Hebrew  locale
if (!ComponentOrientation.getOrientation(Locale.getDefault()).isLeftToRight ()){
   ((JLabel)table.getDefaultRenderer(String.class)).setHorizontalAlignment (JLabel.RIGHT);
}

圖 8. JTable 內的文字右對齊

對齊方式

javax.swing.JLabel 是一個 GUI 開發中非常常用的控件,可以用來展示界面上的文字內 容。通常來講,使用 JLabel 控件是遵循 ComponentOrientation 指定的全局方向的。但是 如果用戶強制使用代碼指定了控件的顯示方向,新的設置將覆蓋 ComponentOrientation 的 全局方向。

JLabel label = new JLabel(text, icon, SwingConstants.LEFT);

label.setHorizontalAlignment(SwingConstants.LEFT);

為了使控件能夠按照 ComponentOrientation 指定的全局方向顯示內容,開發人員應該避 免在生成控件或者指定對齊方式的時候,使用左常量 SwingConstants.LEFT,右常量 SwingConstants.RIGHT。開發人員應該使用專門支持 BiDi 的常量 SwingConstants.LEADING ,SwingConstants.TRAILING 來指定對齊方式。

在使用 JLabel 和 JButton 控件的時候,需要注意對齊方式的取值問題。當然對於繼承 了這兩個類的控件,例如 class DefaultTableCellRenderer extends JLabel,也需要注意 不要直接使用左常量 SwingConstants.LEFT,右常量 SwingConstants.RIGHT。

Eclipse 對 BiDi 的支持

Eclipse 是目前開發人員最為推崇的 Java 集成開發工具。Eclipse 的圖形開發可以基於 Eclipse 特有的 SWT 和 JFace 架構。

圖 9. Eclipse Platform architecture

前面已經說過 Swing 是純 Java 的實現,而 SWT 則有點類似與 AWT,是 Java 與 JNI 的混合,當然具體的實現和 AWT 是完全不同的。至於 Swing 和 SWT 的優劣比較,不在本文 的介紹范圍之內。這方面的內容在網絡上有很多,仁者見仁,智者見智。

回到本文,因為 Eclipse 采用了和 Swing 截然不同的圖形庫,在 BiDi 支持方面也有不 同的要求。根據筆者的開發經驗,在 Eclipse 上開發圖形應用程序,基本上不需要特殊的編 程處理,BiDi 的實現細節都已經封裝在 SWT/JFace 的圖形控件裡面。只需要將區域設置設 定為雙向字符集的地區,啟動 Eclipse 應用程序,程序就會自動啟動 BiDi 的支持。

總體來說,采用 Eclipse 開發支持 BiDi 的 Java 圖形應用,相對於 Swing 來說,工作 量大為減輕。

常見 BiDi 問題以及分析,解決技巧

LRM(\u200F)/RLM(\u200E) 符號的使用

在雙向字符集語言中,標點符號的處理是 BiDi 算法中一個需要特別關注的地方。在 BiDi 中,所有的非標點符號被稱為“強”字符。而標點符號既可以是從左向右 LTR 也可以 是從右向左 RTL。因為不含任何的方向信息,所以被稱為“弱”字符。通常是由軟件根據 BiDi 算法來決定標點符號放置的方向。

在 BiDi 算法中,如果標點符號放在兩段有相同方向文字的中間,標點符號將繼承相同的 方向。如果標點符號放在兩段有不同方向的文字中間,標點符號將繼承全局方向。如果一個 “弱”字符緊挨著一個“弱”字符,BiDi 算法將根據最近相鄰的“強”字符來決定字符方向 。在某些情況下,這會導致非預期的情況出現。為了糾正錯誤,需要使用“偽強”字符 (U200E RLM 或者 U200F RLM)插入到文字中間來調整字符的顯示。下面就用具體的示例來 說明如何使用這兩個符號來調整內容的顯示。

有如下一段英文“UDDI inquiry URL:”,開發人員要將這段文字的阿拉伯文字(單詞 UDDI 和 URL 不需要翻譯)在界面上用 JLabel 控件展示出來,並注意 對齊方式 章節涉及 的內容。在界面上文字的顯示如圖 10 所示。

圖 10. 標點符號在右側

這段文字的阿拉伯資源為“URL \u0644\u0637\u0644\u0628 UDDI:”,標點符號在顯示的 時候應該在英文單詞的左側,而實際上 Swing 卻把這個符號顯示在了右側,甚至把兩側的英 文顯示也顛倒了。

為了正確的顯示這段文字,開發人員需要在上面的阿拉伯資源前增加一個 LRM(\u200F) 來強行指定文字的方向。文字的正確顯示如圖 11 所示

String text = new String(“ text to be displayed”);
if (!ComponentOrientation.getOrientation(Locale.getDefault()).isLeftToRight ()){
   text = "\u200F " + text;// $NON-NLS-1$
}
JLabel label = new JLabel(text, SwingConstants.LEADING);

圖 11. 標點符號在左側

BiDi 的例外情況處理 URL/文件路徑/XPath

在雙向字符集文字中,界面的全局方向一般都是從右到左(RTL),但是對於一些特殊的 內容 URL(例如 http://www.ibm.com)、文件路徑(例如 c:\windows)、XPath(例如 /bookstore/book)等,在任何情況都需要保持從左到右的方向。也就是說這些內容在雙向字 符集和非雙向字符集中的顯示都應相同。如有不同,就需要開發人員的處理。

問題分析 – 代碼還是資源

很多情況下,因為大部分開發人員並不認識雙向字符集文字,開發人員就不能確定到底是 資源的問題還是代碼的問題。如果有一個方法能夠使開發人員清楚正確的顯示是什麼樣子, 那麼對於解決問題會很有幫助。下面就具體介紹這樣一個方法。

開發人員都知道 Java 中,非英文資源串的存放一般是使用 Unicode 編碼(如果對 Java 國際化資源管理不了解,請參看其他文檔),例如下面的阿拉伯文字資源:

LABEL_TAG=URL \u0644\u0637\u0644\u0628 UDDI:

其對應的英文資源是:

LABEL_TAG=UDDI inquiry URL:

如果希望看到這些阿拉伯資源在 BiDi 下的如何正確顯示,請按照下面幾個步驟操作:

1) 利用資源分析工具 Unicode Code Converter v7 轉換 unicode。將資源“URL \u0644\u0637\u0644\u0628 UDDI:”拷貝到 Mixed input 編輯框中,然後點擊按鈕 Convert ,轉換後的字符就顯示在下面的各個編輯框中,如下圖所示:

圖 12. Unicode Code Converter v7

2)利用 IE 或者 Firefox 浏覽器觀看 BiDi 字符的顯示。在這裡把浏覽器作為 BiDi 顯 示的基准軟件,將 Unicode Code Converter 軟件上的 Characters 編輯框中的內容拷貝出 來,然後粘貼到在從右到左 RTL 模式下啟動的浏覽器中(本文中,筆者使用了 IE)。讀者 可以看到在浏覽器裡內容的顯示是和圖 11 是一致的。如果開發人員開發的應用程序的內容 的顯示與浏覽器裡內容顯示不一致,就需要開發人員參照本文上面論述過內容,檢查代碼來 進一步處理。

圖 13. 在 IE 裡面顯示 BiDi 字符

總結

通過閱讀本文,Java 開發人員能夠從中獲得 BiDi 支持相關的知識,並且能夠從示例和 代碼片段中掌握 BiDi 的開發技能以及 BiDi 問題的解決技巧。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved