OSDN Git Service

Merge release/v3.122.2
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / corelib / I18nText.java
1 /*
2  * internationalization text
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.corelib;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Locale;
14 import java.util.Map;
15 import java.util.Set;
16
17 /**
18  * 多言語のバリアントを持つ文字列情報。
19  * 言語はISO639言語コードで区別される。
20  * <ul>
21  * <li>プライマリ:識別子にはこちらを使う。
22  * 基本はMMD発祥の地に敬意を表して日本語。
23  * <li>グローバル:基本は英語。UCS Basic-Latinオンリーの貧弱な言語環境でも
24  * 読める文字列が望ましい。
25  * <li>その他:必要に応じて好きな言語を。
26  * </ul>
27  */
28 public class I18nText implements CharSequence {
29
30     /** プライマリ言語のロケール。 */
31     public static final Locale LOCALE_PRIMARY = Locale.JAPANESE;
32     /** プライマリ言語のISO639言語コード。 */
33     public static final String CODE639_PRIMARY =
34             LOCALE_PRIMARY.getLanguage();
35
36     /** グローバル言語のロケール。 */
37     public static final Locale LOCALE_GLOBAL = Locale.ENGLISH;
38     /** グローバル言語のISO639言語コード。 */
39     public static final String CODE639_GLOBAL =
40             LOCALE_GLOBAL.getLanguage();
41
42     static{
43         assert "ja".equals(CODE639_PRIMARY);
44         assert "en".equals(CODE639_GLOBAL);
45     }
46
47
48     /**
49      * キーはISO639、値は多言語テキスト。
50      */
51     private final Map<String, String> nameMap = new HashMap<>();
52
53
54     /**
55      * コンストラクタ。
56      */
57     public I18nText(){
58         super();
59         return;
60     }
61
62     /**
63      * プライマリ文字列の登録。
64      * @param seq プライマリ文字列。nullの場合は削除動作
65      */
66     public void setPrimaryText(CharSequence seq){
67         setI18nText(CODE639_PRIMARY, seq);
68         return;
69     }
70
71     /**
72      * グローバル文字列の登録。
73      * @param seq グローバル文字列。nullの場合は削除動作
74      */
75     public void setGlobalText(CharSequence seq){
76         setI18nText(CODE639_GLOBAL, seq);
77         return;
78     }
79
80     /**
81      * 任意のロケールに関連付けられた文字列の登録。
82      * @param locale ロケール
83      * @param seq 文字列。nullの場合は削除動作
84      * @throws NullPointerException ロケール引数がnull
85      */
86     public void setI18nText(Locale locale, CharSequence seq)
87             throws NullPointerException{
88         String code639 = locale.getLanguage();
89         setI18nText(code639, seq);
90         return;
91     }
92
93     /**
94      * 任意の言語コードに関連付けられた文字列の登録。
95      * @param code639 ISO639言語コード
96      * @param seq 文字列。nullの場合は削除動作
97      * @throws NullPointerException 言語コードがnull
98      */
99     public void setI18nText(String code639, CharSequence seq)
100             throws NullPointerException{
101         if(code639 == null) throw new NullPointerException();
102
103         if(seq != null){
104             String text = seq.toString();
105             this.nameMap.put(code639, text);
106         }else{
107             this.nameMap.remove(code639);
108         }
109
110         return;
111     }
112
113     /**
114      * プライマリ文字列を返す。
115      * @return 文字列。見つからなければnullを返す。
116      */
117     public String getPrimaryText(){
118         String result = getI18nText(CODE639_PRIMARY);
119         return result;
120     }
121
122     /**
123      * グローバル文字列を返す。
124      * @return 文字列。見つからなければnullを返す。
125      */
126     public String getGlobalText(){
127         String result = getI18nText(CODE639_GLOBAL);
128         return result;
129     }
130
131     /**
132      * ロケールに応じた文字列を返す。
133      * @param locale ロケール
134      * @return 文字列。見つからなければnullを返す。
135      * @throws NullPointerException 引数がnull
136      */
137     public String getI18nText(Locale locale) throws NullPointerException{
138         String code639 = locale.getLanguage();
139         String result = getI18nText(code639);
140         return result;
141     }
142
143     /**
144      * 言語コードに応じた文字列を返す。
145      * @param code639 ISO639言語コード
146      * @return 文字列。見つからなければnullを返す。
147      * @throws NullPointerException 引数がnull
148      */
149     public String getI18nText(String code639) throws NullPointerException{
150         if(code639 == null) throw new NullPointerException();
151         String result = this.nameMap.get(code639);
152         return result;
153     }
154
155     /**
156      * プライマリ文字列を返す。
157      *
158      * <p>見つからなければグローバル文字列を返す。
159      * それでも見つからなければ長さ0の空文字列を返す。
160      *
161      * <p>※決してnullは返さない。
162      *
163      * @return 文字列
164      */
165     public String getText(){
166         String result;
167
168         result = getPrimaryText();
169
170         if(result == null){
171             result = getGlobalText();
172         }
173
174         if(result == null){
175             result = "";
176         }
177
178         return result;
179     }
180
181     /**
182      * 実行環境のデフォルトロケールに応じた文字列を返す。
183      *
184      * <p>見つからなければグローバル文字列、プライマリ文字列の順に返す。
185      * それでも見つからなければ適当な言語コードの文字列を返す。
186      * それでも見つからなければ長さ0の空文字列を返す。
187      *
188      * <p>デフォルトロケールの確認はその都度行われる。
189      *
190      * <p>※決してnullは返さない。
191      *
192      * @return 文字列
193      */
194     public String getLocalizedText(){
195         Locale locale = Locale.getDefault();
196         String langCode = locale.getLanguage();
197
198         String result;
199
200         result = this.nameMap.get(langCode);
201
202         if(result == null){
203             result = this.nameMap.get(CODE639_GLOBAL);
204         }
205
206         if(result == null){
207             result = this.nameMap.get(CODE639_PRIMARY);
208         }
209
210         if(result == null){
211             Set<String> langSet = this.nameMap.keySet();
212             for(String lang : langSet){
213                 result = this.nameMap.get(lang);
214                 if(result != null) break;
215             }
216         }
217
218         if(result == null){
219             result = "";
220         }
221
222         return result;
223     }
224
225     /**
226      * 全言語の文字列を削除する。
227      */
228     public void clearI18nText(){
229         this.nameMap.clear();
230         return;
231     }
232
233     /**
234      * 登録済みの全ISO639言語コードリストを返す。
235      * 優先度はプライマリ、グローバル、その他の順。
236      * @return 全ISO639言語コード
237      */
238     public List<String> lang639CodeList(){
239         Set<String> set = this.nameMap.keySet();
240         List<String> result = new ArrayList<>(set.size());
241
242         for(String lang : set){
243             if(lang.equals(CODE639_PRIMARY)) result.add(lang);
244         }
245
246         for(String lang : set){
247             if(lang.equals(CODE639_GLOBAL)) result.add(lang);
248         }
249
250         for(String lang : set){
251             if(lang.equals(CODE639_PRIMARY)) continue;
252             if(lang.equals(CODE639_GLOBAL)) continue;
253             result.add(lang);
254         }
255
256         return result;
257     }
258
259     /**
260      * プライマリ文字列が登録されているか判定する。
261      * @return 登録されていればtrue
262      */
263     public boolean hasPrimaryText(){
264         boolean result = this.nameMap.containsKey(CODE639_PRIMARY);
265         return result;
266     }
267
268     /**
269      * グローバル文字列が登録されているか判定する。
270      * @return 登録されていればtrue
271      */
272     public boolean hasGlobalText(){
273         boolean result = this.nameMap.containsKey(CODE639_GLOBAL);
274         return result;
275     }
276
277     /**
278      * {@inheritDoc}
279      * {@link #getText()}仕様に準ずる。
280      * @param index {@inheritDoc}
281      * @return {@inheritDoc}
282      */
283     @Override
284     public char charAt(int index){
285         String text = getText();
286         char result = text.charAt(index);
287         return result;
288     }
289
290     /**
291      * {@inheritDoc}
292      * {@link #getText()}仕様に準ずる。
293      * @return {@inheritDoc}
294      */
295     @Override
296     public int length(){
297         String text = getText();
298         int result = text.length();
299         return result;
300     }
301
302     /**
303      * {@inheritDoc}
304      * {@link #getText()}仕様に準ずる。
305      * @param start {@inheritDoc}
306      * @param end {@inheritDoc}
307      * @return {@inheritDoc}
308      */
309     @Override
310     public CharSequence subSequence(int start, int end){
311         String text = getText();
312         CharSequence result = text.subSequence(start, end);
313         return result;
314     }
315
316     /**
317      * {@inheritDoc}
318      * {@link #getText()}仕様に準ずる。
319      * @return {@inheritDoc}
320      */
321     @Override
322     public String toString(){
323         return getText();
324     }
325
326 }