Skip to main content

Software  > Globalization > 

Globalize your On Demand Business

Java 2

Major Bidi-Related classes
ComponentOrientation (see java.awt.ComponentOrientation)
This class is used to specify a Java component's layout direction.

Only Swing components react to ComponentOrientation settings. In general, toggling the ComponentOrientation of a component should modify the geometry layout as well as the text alignment and layout direction within the component. This class is very useful for Bidi languages such as Arabic and Hebrew when display is required to be right to left, as well as for Far Eastern languages where text can go from top to bottom (though current JDKs do not implement this).
Some of the useful methods related to ComponentOrientation are:

  • java.awt.Component.setComponentOrientation(ComponentOrientation o) sets the orientation of the given component. The ComponentOrientation class provides the constants RIGHT_TO_LEFT and LEFT_TO_RIGHT (among others) that can be used as arguments to this function. This does not set the orientation of child components or associated menus, see the JDK 1.4 note below.
  • java.awt.Component.getComponentOrientation() retrieves the language-sensitive orientation that is to be used to order the elements or text within this component.
  • java.awt.ComponentOrientation.isLeftToRight() Returns true for left-to-right component's orientation.
  • java.awt.Window.applyResourceBundle(ResourceBundle rb) applies the default orientation for a given ResourceBundle's locale on a window and its content. Deprecated. As of J2SE 1.4, replaced by Component.applyComponentOrientation.
  • java.awt.ComponentOrientation.getOrientation(ResourceBundle bdl)returns the default orientation appropriate for a given ResourceBundle's localization. Deprecated. As of J2SE 1.4, use getOrientation(java.util.Locale).
  • java.awt.Container.applyComponentOrientation(ComponentOrientation o). This sets the ComponentOrientation property of this container and all components contained within it. Using this method developers won't need to fetch all children of a container to change their ComponentOrientation, instead this method will propagate the orientation to the container and all its children. This method exists since JDK 1.4.

TextLayout (see java.awt.font.TextLayout)
This class provides access to metric and selection information about a line of text.

TextLayout implements all Java built-in Bidi text functionality related to character reordering. It also handles the mapping between the characters position in the storage buffer and the display, the caret position, logical and visual highlighting, metric information and rendering. It is used in Java for rendering and calculation of text dimensions.

It behaves according to the Unicode 3.0 standards. By default it uses contextual reading order.

TextLayout provides the following capabilities:

  • implicit bidirectional analysis and reordering,
  • cursor positioning and movement, including split cursors for mixed directional text,
  • highlighting, including both logical and visual highlighting for mixed directional text,
  • multiple baselines (roman, hanging, and centered),
  • hit testing,
  • justification,
  • default font substitution,
  • metric information such as ascent, descent, and advance, and
  • rendering.

NB: In JDK 1.3 and prior, there was no way to control the numerals shapes, they were displayed as stored. So in general they were displayed using Arabic digits (as in English).

In JDK 1.4 a new class was added, java.awt.font.NumericShaper, that performs numeric shaping according to a given attribute. Also, a new TextAttribute was added, java.awt.font.TextAttribute.NUMERIC_SHAPING, which can be applied to a paragraph of text. If a TextLayout is created using text styled with a numeric shaper, it will apply the shaper to the text before laying out the text.

NumericShaper (JDK 1.4 only) (see java.awt.font.NumericShaper)
This class converts decimal digits to decimal digits of other scripts in Unicode 3.0.
The java.awt.font.NumericShaper class is primarily used to convert Latin-1 (European) digits to other Unicode decimal digits. Users of this class will primarily be people who wish to present data using national digit shapes, keeping data internally using Latin-1 (European) digits. This class is very useful in order to overcome the lack of automatic numeric shaping in Swing.

Bidi (JDK 1.4 only) (see java.text.Bidi)
This class implements the Unicode 3.0 Bidi Algorithm.
An instance of the java.text.Bidi class provides information on the bidirectional reordering of the text used to create it. This is required, for example, to properly display Arabic or Hebrew text. Once created, a Bidi object can be queried to see if the text it represents is all left-to-right or all right-to-left, and find out other Bidi relevant information. Java usually handles this for you, so this is generally not needed. (It can be used with java.awt.font.GlyphVector to do low-level rendering.)

Swing components
Swing components are completely pure Java. That's why their Bidi support is independent of the underlying operating system. Bidi support in Swing requires a proper font and Input Method (Keyboard Input).

Below is a summary of the Bidi status of different Swing components, mainly the effect of setting the ComponentOrientation.

Static Components (Non-Editable Components)
Static components depend on the TextLayout class for Bidi text rendering. Almost all static components mirror their geometry according to their ComponentOrientation settings. However, the string reading order is always contextual. If you want a string or paragraph to have a specific reading order, you may insert an LRM or RLM Unicode character (U+200E and U+200F) at the start.

  • JLabel, JButton, JMenuItem, JCheckBoxMenuItem, JMenu, JRadioButtonMenuItem, JToggleButton, JCheckBox, JRadioButton and TitledBorder inherit from javax.swing.SwingConstants static variables used for relative horizontal alignment, called TRAILING and LEADING. These should be used instead of LEFT and RIGHT, for the alignment to be affected according to the ComponentOrientation setting.

For example, JLabel can display either text, or image, or both. Text-only labels are leading edge aligned by default; image-only labels are horizontally centered, by default. You can also specify the position of the text relative to the image. By default, text is on the trailing edge of the image, with the text and image vertically aligned.

A label's leading and trailing edge are determined from the value of its java.awt.ComponentOrientation property. The default ComponentOrientation setting, which is LEFT_TO_RIGHT, maps the leading edge to left and the trailing edge to right. If the ComponentOrientation is set to RIGHT_TO_LEFT, the leading edge is mapped to the right edge and the trailing to the left.

So changing the JLabel ComponentOrientation will change the alignment of the text and images if setHorizontalTextPosition() and setHorizontalAlignment() are using LEADING and TRAILING. However, the alignment will not be affected if these are set using RIGHT and LEFT. Here's an example:

button.setHorizontalAlignment(JButton.LEADING);
button.setHorizontalTextPosition(JButton.TRAILING);
  • The following components horizontally mirror their geometry lay out according to the ComponentOrientation settings: JTree, JSlider, JToolTip, JComboBox, JList, JProgressBar and JScrollPane.
  • In Sun's JDK the ComboBox's edit field does not change its alignment, but the location of its vertical scrollbar is mirrored. It behaves correctly in IBM's JDK.
  • JOptionPane JOptionPane sets orientation of created dialogs and internal frames in accordance with the orientation of their parent component. In Java 1.3, the user should create a dialog using method JOptionPane.createDialog(), and after that apply a new orientation using method applyResourceBundle().
  • JColorChooser Since Java 1.4, JColorChooser automatically inherits orientation from its parent.
  • JSplitPane Currently this component does not have RTL support. Changing of internal components' locations and recalculation of divider’s position in horizontal JSplitPane should be done manually.
  • JTabbedPane. JTabbedPane lets the user switch between a group of components by clicking on a corresponding tab with a given title and/or icon. When tabs are placed on the top or on the bottom of this component, they are aligned to its leading edge in accordance with its current orientation and displayed in the direction from leading to trailing edge. Title of each tab is displayed on the trailing side of icon.  Problem with mirroring appears, when the tabs are placed on the left or on the right side of JTabbedPane, because change of orientation does not cause moving tabs to the opposite side. To solve this problem method setComponentOrientation() can be overridden, as in following example: 
    JTabbedPane tabPane = new JTabbedPane(JTabbedPane.LEFT) {
          public void setComponentOrientation(ComponentOrientation co) {
                  super.setComponentOrientation(co);
                  if (getTabPlacement() == JTabbedPane.LEFT)
                    setTabPlacement(JTabbedPane.RIGHT);
                 else if (getTabPlacement() == JTabbedPane.RIGHT)
                    setTabPlacement(JTabbedPane.LEFT);
          } 
    }; 

    Since Java 1.4, JTabbedPane can be displayed with two different layouts of its tabs. When SCROLL_TAB_LAYOUT policy is set, tabs are placed within the scrollable region and an additional pair of scroll buttons is provided for the user to control the scrolling. Unfortunately, this does not work properly with RTL-oriented JTabbedPane (both Java IBM 1.4.1 and Sun 1.4.2 were checked), therefore this tab layout currently cannot be recommended for Bidi development.

  • JTable This component has RTL support since Java 1.4. With Java 1.4, RTL-oriented JTable behaves correctly, which means that:
    1. columns with their headers are laid out in RTL sequence,
    2. the table is aligned to the right side of its panel,
    3. the table and its columns are resized from the left,
    4. the direction of the focus transfer between editable cells is right to left, top to bottom.

JText Components
JTextField and JTextArea:

  • Are fully Bidi enabled. They properly handle text entry, display, cursor movement, cut, copy and paste. Cursor movement is visual (follows order of the characters on the screen). Selection is logical.
  • Properly react to the ComponentOrientation, by changing the text alignment and its reading order to follow the ComponentOrientation.
  • Users can change the orientation by using the Alt+Enter or ctrl+Shift+o keys in IBM's JDK and ctrl+Shift+o in Sun's JDK.
  • By default, if ComponentOrientation is not set, or ScreenReverse is not used, the text reading order is contextual.

JTextPane, JTextEditor and JEditorPane:

  • Are similar to JTextArea, but don't mirror their geometry according to the ComponentOrientation or user ScreenReverse. Only the text reading order is affected.
  • Allow StyleConstants.setAlignment to be used to set the alignment style of a paragraph or whole document.
  • JEditorPane does not support the <bdo> tag or the DIR attribute
  • JEditorPane does not load the HTML document with charset, defined as ISO-8859-8-I.

This component has two levels of RTL support:

  1. Viewing of JScrollPane itself
  2. Viewing and scrolling of its contents, which can be done only along with JViewport, that has corresponding level of RTL support too.
    1. Vertical scroll bar, when visible, is placed on the trailing side of the given scroll pane. Row header, when used, is placed from its leading side. Positions of components in the corners cannot be defined with existing logical constants like UPPER_LEADING_CORNER (because this cannot be handled and causes termination of program with IllegalArgumentException), and are not changed after changing the scroll pane's orientation.
    2. In Java 1.3, JScrollPane (as well as JViewport) does not have RTL-specific behavior in viewing and scrolling of its contents, therefore it cannot determine correctly the initial position of narrow contents in a wide scroll pane (should be from the right) and the initial position of wide contents in a narrow scroll pane (right side of contents should be visible). It cannot handle visibility of scroll pane's contents from the left, etc. Since Java 1.4 these problems are solved.

HTML
As of JDK 1.3, the Swing text package supports the display and editing of HTML V3.2 specification with some of the HTML 4.0 features, unfortunately this feature does not include the Bidi features of HTML 4.0, however we can achieve suitable results by inserting LRM / RLM or LRE/RLE markers (and align="right" attribute) to the start of each new line of HTML document.

AWT
Bidi in AWT components is taken from their peer components in the underlying operating system. To get proper Bidi enablement in Java components, the running operating system should be Bidi-enabled (e.g. Arabic or Hebrew windows).

Orientation and other Bidi attributes cannot be set from within the application, they take their settings from the System Regional Settings.

Components set their Orientation to be the same as the default Orientation for the system current default keyboard. If the default input keyboard is Arabic/Hebrew the orientation is set to RTL.

There is no Bidi support in AWT under Linux.

The following (Table 1) shows Bidi support under different MS Windows platforms. WinXP has not been tested yet.

 

Win 95/98

Win NT and Win2K

OS Language

English

Arabic/Hebrew

Default English

Default is
Arabic/Hebrew

Text Display

False 

True 

False 

True 

Text Input

False 

True

False 

True

Enablement

False 

True

False 

True 

Orientation 

False 

The system keyboard default orientation

False 

The system keyboard default orientation











Table 1

Containers & Layout Managers
Most of the standard layout managers let the container mirror its content, when its ComponentOrientation property is changed. Some Bidi layout's specify constants that can be used for this purpose.

  • FlowLayout: the FlowLayout manager arranges components in a left-to-right or right-to-left flow in accordance with the orientation of its container. Each row of components is justified to the leading edge of the container by default. The constants LEADING and TRAILING can be used to define the direction of this justification.
  • BorderLayout: the BorderLayout manager lays out a container, arranging its components to fit in five regions: North, South, East, West and center. It provides the user with constants BEFORE_LINE_BEGINS and AFTER_LINE_ENDS for arranging components in the East (right) and West (left) regions of its container. When the orientation of the container is RTL, these constants map to East and West respectively. When the orientation is LTR, they map to West and East.
  • GridLayout: the GridLayout manager lays out a container's components in a rectangular grid. In Java 1.3, it does not have RTL support and always places each next column of components on the right side of the previous one. Since Java 1.4, it honors changes of the container's orientation and places each next column on the trailing side of the previous one.
  • BoxLayout: the BoxLayout manager allows multiple components to be laid out either vertically or horizontally inside of their container. In Java 1.3, it does not have RTL support and arranges components horizontally from left to right in the same order they were added to the container. Since Java 1.4, it honors changes of the container's orientation and arranges components horizontally in the direction from the leading to the trailing edge of their container.
  • GridBagLayout: the GridBagLayout manager aligns components vertically and horizontally in a rectangular grid of cells, where components can be of different sizes and each component can occupy more than one cell. In Java 1.3, it does not have RTL support and does not honor orientation changes of the container. Since Java 1.4, the orientation of the grid depends on the container's ComponentOrientation property, and grid coordinate (0,0) is in the upper leading corner of the container with x increasing towards the trailing direction.
    Each component managed by GridBagLayout is associated with an instance of GridBagConstraints which specifies the location of the component in the grid and its position within the allowed display area. When the component is smaller than the area where it should be displayed, its position can be defined using logical constants which are used as values of the GridBadConstraints.anchor variable, like LINE_START, FIRST_LINE_START, LAST_LINE_START (at the leading edge on the center, top or bottom) and LINE_END, FIRST_LINE_END and LAST_LINE_END (at the trailing edge on the center, top or bottom).

Bidi RichEdit Control (TextPanel)
The RichEdit control is a pure Java component developed by the IBM Java Technology Center (JTC) several years ago, in order to offer a text component that is fully Bidi enabled even if the underlying OS is not. It is designed so that it relies on the TextLayout class in JDK 1.2 to get the required Bidi functionality. It works with JDK 1.2 and 1.3, but not 1.1 or (currently) 1.4. It supports both text and paragraph styles, and much of the functionality of AWT's TextArea. It also provides contextual orientation (i.e. Alignment and TextOrientation are determined by the first strong character in the line).

The RichEdit control is available as part of ICU4J, an open-source project promoted by IBM. For more information about this component go to oss.software.ibm.com/icu4j.

The drawString methods
The drawString group of methods in java.awt.Graphics and java.awt.Graphics2D use the TextLayout class to reorder and shape Bidi text for rendering. Thus you can use Graphics.drawString to render single lines of Bidi text.

Note that this causes Bidi analysis to be performed once per string. Bidi analysis should be performed once per paragraph, so this technique should not be used unless the string is the entire text of the paragraph.

Keyboard, InputMethod
Input Method Framework (IMF) packages can be used to create a language specific input method as an extension to JVM. This allows users to enter text on any operating system even if it does not support their language, because the input method intercepts the text input and converts it to the target languages. Input methods are designed to support particular languages.

Printing
Users can print Bidi data using the graphics functions. However, with JDK 1.2 it is working only under Win NT and Win2K.

Locales
All the locale definitions (13 Arabic and 1 Hebrew) are defined properly. Below is an example on how to query the locale information.

Example for how to query the locale information

import java.util.*;
import java.text.*;
import java.io.*;
import java.awt.*;
public class Locales extends Frame{
     static BufferedWriter out;

     static public void displayNumber(Locale currentLocale) {
      Integer quantity = new Integer(123456);
      Double amount = new Double(345987.246);
      NumberFormat numberFormatter;
      String quantityOut;
      String amountOut;
      numberFormatter = NumberFormat.getNumberInstance(currentLocale);
      quantityOut = numberFormatter.format(quantity);
      amountOut = numberFormatter.format(amount);
      System.out.println("Integer :  " + quantityOut + "   " );
      System.out.println("Float :  " + amountOut + "   " );
   }
   static public void displayCurrency(Locale currentLocale) {
      Double currency = new Double(9876543.21);
      NumberFormat currencyFormatter;
      String currencyOut;
      currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
      currencyOut = currencyFormatter.format(currency);
      System.out.println("Currency :  " +currencyOut );
   }
   static public void displayPercent(Locale currentLocale) {
      Double percent = new Double(0.75);
      NumberFormat percentFormatter;
      String percentOut;
      percentFormatter = NumberFormat.getPercentInstance(currentLocale);
      percentOut = percentFormatter.format(percent);
      System.out.println("Percent :  " + percentOut + "   " + currentLocale.toString());
   }
   static public void displayDate(Locale currentLocale) {
      Date today;
      String dateOut;
      DateFormat dateFormatter;
      dateFormatter =
         DateFormat.getDateInstance(DateFormat.DEFAULT, currentLocale);
      today = new Date();
      dateOut = dateFormatter.format(today);
      System.out.println("Date :  " + dateOut + "   " );
   }
   static public void displayLongDateTime(Locale currentLocale) {
      Date today;
      String result;
      DateFormat formatter;
      formatter =
        DateFormat.getDateTimeInstance(DateFormat.LONG,
                                        DateFormat.LONG,
                                        currentLocale);
      today = new Date();
      result = formatter.format(today);
      System.out.println("LongDate&Time :  " + result );
   }
   static public void showDateStyles(Locale currentLocale) {
      Date today = new Date();
      String result;
      DateFormat formatter;
      int[] styles = {
         DateFormat.DEFAULT,
         DateFormat.SHORT,
         DateFormat.MEDIUM,
         DateFormat.LONG,
         DateFormat.FULL
      };
      String[] style = {
        "Default",
        "Short",
        "Medium",
        "Long",
        "Full"
      };
      System.out.println("Date Styles : ");
      for (int k = 0; k < styles.length; k++) {
         formatter =  DateFormat.getDateInstance(styles[k], currentLocale);
         result =  formatter.format(today);
         System.out.println(style[k] +" :  " + result);
      }
   }
   static public void showTimeStyles(Locale currentLocale) {
      Date today = new Date();
      String result;
      DateFormat formatter;
      int[] styles = {
         DateFormat.DEFAULT,
         DateFormat.SHORT,
         DateFormat.MEDIUM,
         DateFormat.LONG,
         DateFormat.FULL
      };
      String[] style = {
        "Default",
        "Short",
        "Medium",
        "Long",
        "Full"
      };
      System.out.println("Time Styles :  ");
      for (int k = 0; k < styles.length; k++) {
         formatter =
            DateFormat.getTimeInstance(styles[k], currentLocale);
         result = formatter.format(today);
      System.out.println(style[k] +" :  " + result);
      }
   }
   static public void main(String[] args) {
      Locale locales[] = DateFormat.getAvailableLocales();
      for (int i = 0; i < 20; i++) {
         System.out.println("           ----------------");
         System.out.println("Locale: " + locales[i]);
         System.out.println("\nLanguage :  " + locales[i].getDisplayLanguage());
         System.out.println("\nCountry :  " + locales[i].getDisplayCountry());
         System.out.println("\nMonths :");
         DateFormatSymbols symbols = new DateFormatSymbols(locales[i]);
         String[] months = symbols.getMonths();
         String[] smallmonth = symbols.getShortMonths();
         for(int j=0;j<12;j++){
             System.out.println("\n" + months[j] + " , " + smallmonth[j]);
         }
         System.out.println("\nDays of the week :");
         String[] week = symbols.getWeekdays();
         String[] smallweek = symbols.getShortWeekdays();
         for(int j=1;j<8;j++){
             System.out.println("\n" + week[j] + " , " + smallweek[j]);
         }
         displayDate(locales[i]);
         showDateStyles(locales[i]);
         showTimeStyles(locales[i]);
         System.out.println();
         displayLongDateTime(locales[i]);
         System.out.println();
         displayNumber(locales[i]);
         displayCurrency(locales[i]);
         displayPercent(locales[i]);
      }
   }
}

Data Interchange
Java provides the CharToByte and ByteToChar methods to convert data between Unicode and other code pages. However, if an application is interacting with legacy data, such as data stored on iSeries or zSeries, some extra transformation is required to convert the data between the visual format (legacy storage format) and the logical format (used by new applications).

The Arabic code pages are:

  • Cp420 for z/OS and iSeries
  • Cp425 for zSeries USS
  • ISO8859-6 for Unix and Mac
  • Cp864 for OS/2
  • Cp1256 for MS Windows

The Hebrew code pages are:

  • Cp424 for z/OS and iSeries
  • ISO8859-8 for Unix and Mac
  • Cp862 for OS/2
  • Cp1255 for MS Windows

In JDK 1.3.1 and prior, these converters are implemented internally in sun.io and have names like ByteToCharCp1250. They are used internally by java.util.String, java.io.InputStreamReader and java.io.OutputStreamWriter.

But in JDK 1.4, new public classes were added, to be used to convert between 16-bit Unicode (Java char) and other code pages. These classes are:

  • java.nio.charset.Charset: This class defines methods for creating decoders and encoders and for retrieving the various names associated with a charset.
  • java.nio.charset.CharsetDecoder: This class defines an engine that can transform a sequence of bytes in a specific charset into a sequence of sixteen-bit Unicode characters.
  • java.nio.charset.CharsetEncoder: This class defines an engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of bytes in a specific charset.


gray line

Continue to JDK 1.1.x


E-mail us
Easy ways to get the answers you need.
E-mail us