Multilingual.java
     1: //========================================================================================
     2: //  Multilingual.java
     3: //    en:Multilingual
     4: //    ja:多言語化
     5: //  Copyright (C) 2003-2019 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //  あらかじめ英語のテキストを設定しておく
    15: //  言語はISO 639 alpha-2の文字列("ja"など)で指定する
    16: //  text
    17: //    AbstractButton
    18: //      JButton
    19: //        BasicArrowButton
    20: //          MetalScrollButton
    21: //        MetalComboBoxButton
    22: //      JMenuItem
    23: //        JCheckBoxMenuItem
    24: //        JMenu
    25: //        JRadioButtonMenuItem
    26: //      JToggleButton
    27: //        JCheckBox
    28: //        JRadioButton
    29: //    JLabel
    30: //      BasicComboBoxRenderer
    31: //        BasicComboBoxRenderer.UIResource
    32: //      DefaultListCellRenderer
    33: //        DefaultListCellRenderer.UIResource
    34: //        MetalFileChooserUI.FileRenderer
    35: //        MetalFileChooserUI.FilterComboBoxRenderer
    36: //      DefaultTableCellRenderer
    37: //        DefaultTableCellRenderer.UIResource
    38: //      DefaultTreeCellRenderer
    39: //    JTextComponent
    40: //      JEditorPane
    41: //        JTextPane
    42: //      JTextArea
    43: //      JTextField
    44: //        DefaultTreeCellEditor.DefaultTextField
    45: //        JFormattedTextField
    46: //        JPasswordField
    47: //  title
    48: //    Dialog
    49: //      FileDialog
    50: //      JDialog
    51: //    Frame
    52: //      JFrame
    53: //    TitledBorder
    54: //  toolTipText
    55: //    JComponent
    56: //----------------------------------------------------------------------------------------
    57: 
    58: package xeij;
    59: 
    60: import java.awt.*;  //BasicStroke,BorderLayout,BoxLayout,Color,Component,Container,Cursor,Desktop,Dimension,Font,Frame,Graphics,Graphics2D,GraphicsDevice,GraphicsEnvironment,GridLayout,Image,Insets,Paint,Point,Rectangle,RenderingHints,Robot,Shape,Stroke,TexturePaint,Toolkit
    61: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    62: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    63: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    64: import javax.swing.*;  //AbstractButton,AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    65: import javax.swing.border.*;  //Border,CompoundBorder,EmptyBorder,EtchedBorder,LineBorder,TitledBorder
    66: 
    67: public class Multilingual {
    68: 
    69:   //多言語化マップ
    70:   public static HashMap<AbstractButton,HashMap<String,String>> mlnButtonTextMap;  //ボタンのテキスト
    71:   public static HashMap<JLabel,HashMap<String,String>> mlnLabelTextMap;  //ラベルのテキスト
    72:   public static HashMap<Dialog,HashMap<String,String>> mlnDialogTitleMap;  //ダイアログのタイトル
    73:   public static HashMap<Frame,HashMap<String,String>> mlnFrameTitleMap;  //フレームのタイトル
    74:   public static HashMap<JComponent,HashMap<String,String>> mlnComponentToolTipTextMap;  //コンポーネントのツールチップテキスト
    75:   public static HashMap<SpinnerListModel,HashMap<String,java.util.List<?>>> mlnSpinnerListModelListMap;  //スピナーリストモデルのリスト
    76:   public static HashMap<JComponent,HashMap<String,String>> mlnComponentTitledBorderMap;  //コンポーネントのタイトル付きボーダー
    77: 
    78:   //現在の言語
    79:   public static String mlnLang;  //現在の言語
    80:   public static boolean mlnEnglish;  //mlnLang.equals("en");
    81:   public static boolean mlnJapanese;  //mlnLang.equals("ja");
    82: 
    83:   //mlnInit ()
    84:   //  多言語化を初期化する
    85:   //  コンポーネントを作る前に呼び出すこと
    86:   public static void mlnInit () {
    87:     //多言語化マップ
    88:     mlnButtonTextMap = new HashMap<AbstractButton,HashMap<String,String>> ();  //ボタンのテキスト
    89:     mlnLabelTextMap = new HashMap<JLabel,HashMap<String,String>> ();  //ラベルのテキスト
    90:     mlnDialogTitleMap = new HashMap<Dialog,HashMap<String,String>> ();  //ダイアログのタイトル
    91:     mlnFrameTitleMap = new HashMap<Frame,HashMap<String,String>> ();  //フレームのタイトル
    92:     mlnComponentToolTipTextMap = new HashMap<JComponent,HashMap<String,String>> ();  //コンポーネントのツールチップテキスト
    93:     mlnSpinnerListModelListMap = new HashMap<SpinnerListModel,HashMap<String,java.util.List<?>>> ();  //スピナーリストモデルのリスト
    94:     mlnComponentTitledBorderMap = new HashMap<JComponent,HashMap<String,String>> ();  //コンポーネントのタイトル付きボーダー
    95:     mlnLang = "";  //現在の言語
    96:     String defaultLang = Locale.getDefault ().getLanguage ();  //動作環境の言語
    97:     mlnChange (defaultLang.equals ("ja") ? "ja" : "en");
    98:   }  //mlnInit()
    99: 
   100:   //mlnChange (lang)
   101:   //  多言語化されたコンポーネントの言語を切り替える
   102:   //  コンポーネントが指定された言語のテキストを持たないときは英語になる
   103:   public static void mlnChange (String lang) {
   104:     if (!mlnLang.equals (lang)) {  //現在の言語と異なるとき
   105:       //現在の言語
   106:       if (lang.equals ("ja")) {
   107:         mlnLang = "ja";
   108:         mlnEnglish = false;
   109:         mlnJapanese = true;
   110:         System.out.println ("日本語が選択されました");
   111:       } else {
   112:         mlnLang = "en";
   113:         mlnEnglish = true;
   114:         mlnJapanese = false;
   115:         System.out.println ("English is selected");
   116:       }
   117:       //ボタンのテキストの言語を切り替える
   118:       for (Map.Entry<AbstractButton,HashMap<String,String>> entry : mlnButtonTextMap.entrySet ()) {
   119:         mlnChangeButtonText (entry.getKey (), entry.getValue (), lang);
   120:       }
   121:       //ラベルのテキストの言語を切り替える
   122:       for (Map.Entry<JLabel,HashMap<String,String>> entry : mlnLabelTextMap.entrySet ()) {
   123:         mlnChangeLabelText (entry.getKey (), entry.getValue (), lang);
   124:       }
   125:       //ダイアログのタイトルの言語を切り替える
   126:       for (Map.Entry<Dialog,HashMap<String,String>> entry : mlnDialogTitleMap.entrySet ()) {
   127:         mlnChangeDialogTitle (entry.getKey (), entry.getValue (), lang);
   128:       }
   129:       //フレームのタイトルの言語を切り替える
   130:       for (Map.Entry<Frame,HashMap<String,String>> entry : mlnFrameTitleMap.entrySet ()) {
   131:         mlnChangeFrameTitle (entry.getKey (), entry.getValue (), lang);
   132:       }
   133:       //コンポーネントのツールチップテキストの言語を切り替える
   134:       for (Map.Entry<JComponent,HashMap<String,String>> entry : mlnComponentToolTipTextMap.entrySet ()) {
   135:         mlnChangeComponentToolTipText (entry.getKey (), entry.getValue (), lang);
   136:       }
   137:       //スピナーリストモデルのリストの言語を切り替える
   138:       for (Map.Entry<SpinnerListModel,HashMap<String,java.util.List<?>>> entry : mlnSpinnerListModelListMap.entrySet ()) {
   139:         mlnChangeSpinnerListModelList (entry.getKey (), entry.getValue (), lang);
   140:       }
   141:       //コンポーネントのタイトル付きボーダーの言語を切り替える
   142:       for (Map.Entry<JComponent,HashMap<String,String>> entry : mlnComponentTitledBorderMap.entrySet ()) {
   143:         mlnChangeComponentTitledBorder (entry.getKey (), entry.getValue (), lang);
   144:       }
   145:     }
   146:   }  //mlnChange(String)
   147: 
   148:   //mlnChangeButtonText (button, map, lang)
   149:   //  ボタンのテキストの言語を切り替える
   150:   public static void mlnChangeButtonText (AbstractButton button, HashMap<String,String> map, String lang) {
   151:     button.setText (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   152:   }  //mlnChangeButtonText(AbstractButton,HashMap<String,String>,String)
   153: 
   154:   //mlnChangeLabelText (label, map, lang)
   155:   //  ラベルのテキストの言語を切り替える
   156:   public static void mlnChangeLabelText (JLabel label, HashMap<String,String> map, String lang) {
   157:     label.setText (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   158:   }  //mlnChangeLabelText(JLabel,HashMap<String,String>,String)
   159: 
   160:   //mlnChangeDialogTitle (dialog, map, lang)
   161:   //  ダイアログのタイトルの言語を切り替える
   162:   public static void mlnChangeDialogTitle (Dialog dialog, HashMap<String,String> map, String lang) {
   163:     dialog.setTitle (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   164:   }  //mlnChangeDialogTitle(Dialog,HashMap<String,String>,String)
   165: 
   166:   //mlnChangeFrameTitle (frame, map, lang)
   167:   //  フレームのタイトルの言語を切り替える
   168:   public static void mlnChangeFrameTitle (Frame frame, HashMap<String,String> map, String lang) {
   169:     frame.setTitle (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   170:   }  //mlnChangeFrameTitle(Frame,HashMap<String,String>,String)
   171: 
   172:   //mlnChangeComponentToolTipText (component, map, lang)
   173:   //  コンポーネントのツールチップテキストの言語を切り替える
   174:   public static void mlnChangeComponentToolTipText (JComponent component, HashMap<String,String> map, String lang) {
   175:     component.setToolTipText (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   176:   }  //mlnChangeComponentToolTipText(JComponent,HashMap<String,String>,String)
   177: 
   178:   //mlnChangeSpinnerListModelList (model, map, lang)
   179:   //  スピナーリストモデルのリストの言語を切り替える
   180:   public static void mlnChangeSpinnerListModelList (SpinnerListModel model, HashMap<String,java.util.List<?>> map, String lang) {
   181:     int index = model.getList ().indexOf (model.getValue ());  //選択されている値のインデックス
   182:     java.util.List<?> list = map.containsKey (lang) ? map.get (lang) : map.get ("en");
   183:     model.setList (list);  //チェンジイベントが発生する
   184:     model.setValue (list.get (index));  //同じインデックスで選択し直す
   185:   }  //mlnChangeSpinnerListModelList(SpinnerListModel,HashMap<String,java.util.List<?>>,String)
   186: 
   187:   //mlnChangeComponentTitledBorder (component, map, lang)
   188:   //  コンポーネントのタイトル付きボーダーの言語を切り替える
   189:   public static void mlnChangeComponentTitledBorder (JComponent component, HashMap<String,String> map, String lang) {
   190:     TitledBorder titledBorder = (TitledBorder) component.getBorder ();
   191:     titledBorder.setTitle (map.containsKey (lang) ? map.get (lang) : map.get ("en"));
   192:     component.repaint ();  //TitledBorder.setTitle()だけだとrepaintされず次にウインドウに触れた瞬間に言語が変化するという不自然な動作になる
   193:   }  //mlnChangeComponentTitledBorder(JComponent,HashMap<String,String>,String)
   194: 
   195:   //button = mlnText (button, lang, text, ...)
   196:   //  ボタンに多言語のテキストを設定する
   197:   //  アクションコマンドを英語のテキストとして用いる
   198:   //  必要ならばテキストにニモニックを加える
   199:   public static <T extends AbstractButton> T mlnText (T button, String... langText) {
   200:     String enText = button.getActionCommand ();
   201:     int mnemonic = button.getMnemonic ();
   202:     String mnemonicText = KeyEvent.getKeyText (mnemonic);
   203:     String mnemonicLowerCaseText = mnemonicText.toLowerCase ();
   204:     HashMap<String,String> map = new HashMap<String,String> ();
   205:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   206:       String lang = i < 0 ? "en" : langText[i];
   207:       String text = i < 0 ? enText : langText[i + 1];
   208:       map.put (
   209:         lang,
   210:         mnemonic == KeyEvent.VK_UNDEFINED ||  //ニモニックがない、または
   211:         text.toLowerCase ().indexOf (mnemonicLowerCaseText) >= 0 ? text :  //ニモニックがテキストに含まれるとき
   212:         text + "(" + mnemonicText + ")");  //ニモニックがある、かつ、ニモニックがテキストに含まれないとき
   213:     }
   214:     mlnButtonTextMap.put (button, map);
   215:     mlnChangeButtonText (button, map, mlnLang);  //現在の言語を設定する
   216:     return button;
   217:   }  //mlnText(T extends AbstractButton,String...)
   218: 
   219:   //label = mlnText (label, lang, text, ...)
   220:   //  ラベルに多言語のテキストを設定する
   221:   public static <T extends JLabel> T mlnText (T label, String... langText) {
   222:     String enText = label.getText ();
   223:     HashMap<String,String> map = new HashMap<String,String> ();
   224:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   225:       String lang = i < 0 ? "en" : langText[i];
   226:       String text = i < 0 ? enText : langText[i + 1];
   227:       map.put (lang, text);
   228:     }
   229:     mlnLabelTextMap.put (label, map);
   230:     mlnChangeLabelText (label, map, mlnLang);  //現在の言語を設定する
   231:     return label;
   232:   }  //mlnText(T extends JLabel,String...)
   233: 
   234:   //dialog = mlnTitle (dialog, lang, text, ...)
   235:   //  ダイアログに多言語のタイトルを設定する
   236:   public static <T extends Dialog> T mlnTitle (T dialog, String... langText) {
   237:     String enText = dialog.getTitle ();
   238:     HashMap<String,String> map = new HashMap<String,String> ();
   239:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   240:       String lang = i < 0 ? "en" : langText[i];
   241:       String text = i < 0 ? enText : langText[i + 1];
   242:       map.put (lang, text);
   243:     }
   244:     mlnDialogTitleMap.put (dialog, map);
   245:     mlnChangeDialogTitle (dialog, map, mlnLang);  //現在の言語を設定する
   246:     return dialog;
   247:   }  //mlnTitle(T extends Dialog,String...)
   248: 
   249:   //frame = mlnTitle (frame, lang, text, ...)
   250:   //  フレームに多言語のタイトルを設定する
   251:   public static <T extends Frame> T mlnTitle (T frame, String... langText) {
   252:     String enText = frame.getTitle ();
   253:     HashMap<String,String> map = new HashMap<String,String> ();
   254:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   255:       String lang = i < 0 ? "en" : langText[i];
   256:       String text = i < 0 ? enText : langText[i + 1];
   257:       map.put (lang, text);
   258:     }
   259:     mlnFrameTitleMap.put (frame, map);
   260:     mlnChangeFrameTitle (frame, map, mlnLang);  //現在の言語を設定する
   261:     return frame;
   262:   }  //mlnTitle(T extends Frame,String...)
   263: 
   264:   //component = mlnToolTipText (component, lang, text, ...)
   265:   //  コンポーネントに多言語のツールチップテキストを設定する
   266:   public static <T extends JComponent> T mlnToolTipText (T component, String... langText) {
   267:     String enText = component.getToolTipText ();
   268:     HashMap<String,String> map = new HashMap<String,String> ();
   269:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   270:       String lang = i < 0 ? "en" : langText[i];
   271:       String text = i < 0 ? enText : langText[i + 1];
   272:       map.put (lang, text);
   273:     }
   274:     mlnComponentToolTipTextMap.put (component, map);
   275:     mlnChangeComponentToolTipText (component, map, mlnLang);  //現在の言語を設定する
   276:     return component;
   277:   }  //mlnToolTipText(T extends JComponent,String...)
   278: 
   279:   //spinner = mlnList (spinner, lang, list, ...)
   280:   //mode = mlnList (model, lang, list, ...)
   281:   //  スピナーリストモデルに多言語のリストを設定する
   282:   public static JSpinner mlnList (JSpinner spinner, Object... langList) {
   283:     mlnList ((SpinnerListModel) spinner.getModel (), langList);
   284:     return spinner;
   285:   }  //mlnList(JSpinner,Object...)
   286:   public static SpinnerListModel mlnList (SpinnerListModel model, Object... langList) {
   287:     java.util.List<?> enList = model.getList ();
   288:     HashMap<String,java.util.List<?>> map = new HashMap<String,java.util.List<?>> ();
   289:     for (int i = langList.length > 0 && ((String) langList[0]).equals ("en") ? 0 : -2; i < langList.length; i += 2) {
   290:       String lang = i < 0 ? "en" : (String) langList[i];
   291:       java.util.List<?> list = i < 0 ? enList : (java.util.List<?>) langList[i + 1];
   292:       map.put (lang, list);
   293:     }
   294:     mlnSpinnerListModelListMap.put (model, map);
   295:     mlnChangeSpinnerListModelList (model, map, mlnLang);  //現在の言語を設定する
   296:     return model;
   297:   }  //mlnList(SpinnerListModel,Object...)
   298: 
   299:   //component = mlnTitledBorder (component, lang, text, ...)
   300:   //  コンポーネントのタイトル付きボーダーに多言語のタイトルを設定する
   301:   public static <T extends JComponent> T mlnTitledBorder (T component, String... langText) {
   302:     TitledBorder titledBorder = (TitledBorder) component.getBorder ();
   303:     String enText = titledBorder.getTitle ();
   304:     HashMap<String,String> map = new HashMap<String,String> ();
   305:     for (int i = langText.length > 0 && langText[0].equals ("en") ? 0 : -2; i < langText.length; i += 2) {
   306:       String lang = i < 0 ? "en" : langText[i];
   307:       String text = i < 0 ? enText : langText[i + 1];
   308:       map.put (lang, text);
   309:     }
   310:     mlnComponentTitledBorderMap.put (component, map);
   311:     mlnChangeComponentTitledBorder (component, map, mlnLang);  //現在の言語を設定する
   312:     return component;
   313:   }  //mlnTitledBorder(T extends JComponent,String...)
   314: 
   315: }  //class Multilingual
   316: 
   317: 
   318: