Commit | Line | Data |
---|---|---|
ec1f3444 NR |
1 | package be.nikiroo.utils.resources; |
2 | ||
b3aad1f9 | 3 | import java.awt.Color; |
ec1f3444 NR |
4 | import java.io.BufferedWriter; |
5 | import java.io.File; | |
6 | import java.io.FileInputStream; | |
7 | import java.io.FileOutputStream; | |
8 | import java.io.IOException; | |
9 | import java.io.InputStreamReader; | |
10 | import java.io.OutputStreamWriter; | |
11 | import java.io.Reader; | |
ec1f3444 NR |
12 | import java.io.Writer; |
13 | import java.lang.reflect.Field; | |
14 | import java.util.ArrayList; | |
62c9ec78 | 15 | import java.util.HashMap; |
ec1f3444 NR |
16 | import java.util.List; |
17 | import java.util.Locale; | |
62c9ec78 | 18 | import java.util.Map; |
ec1f3444 NR |
19 | import java.util.MissingResourceException; |
20 | import java.util.PropertyResourceBundle; | |
21 | import java.util.ResourceBundle; | |
22 | ||
ec1f3444 | 23 | /** |
62c9ec78 | 24 | * This class encapsulate a {@link ResourceBundle} in UTF-8. It allows to |
ec1f3444 NR |
25 | * retrieve values associated to an enumeration, and allows some additional |
26 | * methods. | |
62c9ec78 NR |
27 | * <p> |
28 | * It also sports a writable change map, and you can save back the | |
29 | * {@link Bundle} to file with {@link Bundle#updateFile(String)}. | |
ec1f3444 NR |
30 | * |
31 | * @author niki | |
32 | * | |
33 | * @param <E> | |
34 | * the enum to use to get values out of this class | |
35 | */ | |
36 | public class Bundle<E extends Enum<E>> { | |
37 | protected Class<E> type; | |
38 | protected Enum<?> name; | |
487926f7 NR |
39 | private Map<String, String> map; // R/O map |
40 | private Map<String, String> changeMap; // R/W map | |
ec1f3444 NR |
41 | |
42 | /** | |
43 | * Create a new {@link Bundles} of the given name. | |
44 | * | |
45 | * @param type | |
46 | * a runtime instance of the class of E | |
47 | * | |
48 | * @param name | |
49 | * the name of the {@link Bundles} | |
50 | */ | |
51 | protected Bundle(Class<E> type, Enum<?> name) { | |
52 | this.type = type; | |
53 | this.name = name; | |
487926f7 | 54 | this.map = new HashMap<String, String>(); |
62c9ec78 | 55 | this.changeMap = new HashMap<String, String>(); |
e9ca6bb8 | 56 | setBundle(name, Locale.getDefault(), false); |
ec1f3444 NR |
57 | } |
58 | ||
59 | /** | |
60 | * Return the value associated to the given id as a {@link String}. | |
61 | * | |
62 | * @param mame | |
63 | * the id of the value to get | |
64 | * | |
65 | * @return the associated value, or NULL if not found (not present in the | |
66 | * resource file) | |
67 | */ | |
68 | public String getString(E id) { | |
487926f7 | 69 | return getString(id.name()); |
ec1f3444 NR |
70 | } |
71 | ||
62c9ec78 NR |
72 | /** |
73 | * Set the value associated to the given id as a {@link String}. | |
74 | * | |
75 | * @param mame | |
76 | * the id of the value to get | |
77 | * @param value | |
78 | * the value | |
79 | * | |
80 | */ | |
81 | public void setString(E id, String value) { | |
487926f7 | 82 | setString(id.name(), value); |
62c9ec78 NR |
83 | } |
84 | ||
ec1f3444 NR |
85 | /** |
86 | * Return the value associated to the given id as a {@link String} suffixed | |
87 | * with the runtime value "_suffix" (that is, "_" and suffix). | |
487926f7 NR |
88 | * <p> |
89 | * Will only accept suffixes that form an existing id. | |
ec1f3444 NR |
90 | * |
91 | * @param mame | |
92 | * the id of the value to get | |
93 | * @param suffix | |
94 | * the runtime suffix | |
95 | * | |
96 | * @return the associated value, or NULL if not found (not present in the | |
97 | * resource file) | |
98 | */ | |
99 | public String getStringX(E id, String suffix) { | |
100 | String key = id.name() | |
80383c14 | 101 | + (suffix == null ? "" : "_" + suffix.toUpperCase()); |
ec1f3444 | 102 | |
487926f7 NR |
103 | try { |
104 | id = Enum.valueOf(type, key); | |
105 | return getString(id); | |
106 | } catch (IllegalArgumentException e) { | |
107 | ||
ec1f3444 NR |
108 | } |
109 | ||
110 | return null; | |
111 | } | |
112 | ||
62c9ec78 NR |
113 | /** |
114 | * Set the value associated to the given id as a {@link String} suffixed | |
115 | * with the runtime value "_suffix" (that is, "_" and suffix). | |
487926f7 NR |
116 | * <p> |
117 | * Will only accept suffixes that form an existing id. | |
62c9ec78 NR |
118 | * |
119 | * @param mame | |
120 | * the id of the value to get | |
121 | * @param suffix | |
122 | * the runtime suffix | |
123 | * @param value | |
124 | * the value | |
125 | */ | |
126 | public void setStringX(E id, String suffix, String value) { | |
127 | String key = id.name() | |
128 | + (suffix == null ? "" : "_" + suffix.toUpperCase()); | |
129 | ||
487926f7 NR |
130 | try { |
131 | id = Enum.valueOf(type, key); | |
132 | setString(id, value); | |
133 | } catch (IllegalArgumentException e) { | |
134 | ||
135 | } | |
62c9ec78 NR |
136 | } |
137 | ||
ec1f3444 NR |
138 | /** |
139 | * Return the value associated to the given id as a {@link Boolean}. | |
140 | * | |
141 | * @param mame | |
142 | * the id of the value to get | |
143 | * | |
144 | * @return the associated value | |
145 | */ | |
146 | public Boolean getBoolean(E id) { | |
147 | String str = getString(id); | |
148 | if (str != null && str.length() > 0) { | |
149 | if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on") | |
150 | || str.equalsIgnoreCase("yes")) | |
151 | return true; | |
152 | if (str.equalsIgnoreCase("false") || str.equalsIgnoreCase("off") | |
153 | || str.equalsIgnoreCase("no")) | |
154 | return false; | |
155 | ||
156 | } | |
157 | ||
158 | return null; | |
159 | } | |
160 | ||
161 | /** | |
62c9ec78 | 162 | * Return the value associated to the given id as a {@link Boolean}. |
ec1f3444 NR |
163 | * |
164 | * @param mame | |
165 | * the id of the value to get | |
166 | * @param def | |
167 | * the default value when it is not present in the config file or | |
168 | * if it is not a boolean value | |
169 | * | |
170 | * @return the associated value | |
171 | */ | |
172 | public boolean getBoolean(E id, boolean def) { | |
173 | Boolean b = getBoolean(id); | |
174 | if (b != null) | |
175 | return b; | |
176 | ||
177 | return def; | |
178 | } | |
179 | ||
180 | /** | |
181 | * Return the value associated to the given id as an {@link Integer}. | |
182 | * | |
183 | * @param mame | |
184 | * the id of the value to get | |
185 | * | |
186 | * @return the associated value | |
187 | */ | |
188 | public Integer getInteger(E id) { | |
189 | try { | |
190 | return Integer.parseInt(getString(id)); | |
191 | } catch (Exception e) { | |
192 | } | |
193 | ||
194 | return null; | |
195 | } | |
196 | ||
197 | /** | |
198 | * Return the value associated to the given id as a {@link int}. | |
199 | * | |
200 | * @param mame | |
201 | * the id of the value to get | |
202 | * @param def | |
203 | * the default value when it is not present in the config file or | |
204 | * if it is not a int value | |
205 | * | |
206 | * @return the associated value | |
207 | */ | |
208 | public int getInteger(E id, int def) { | |
209 | Integer i = getInteger(id); | |
210 | if (i != null) | |
211 | return i; | |
212 | ||
213 | return def; | |
214 | } | |
215 | ||
216 | /** | |
217 | * Return the value associated to the given id as a {@link Character}. | |
218 | * | |
219 | * @param mame | |
220 | * the id of the value to get | |
221 | * | |
222 | * @return the associated value | |
223 | */ | |
62c9ec78 | 224 | public Character getCharacter(E id) { |
ec1f3444 NR |
225 | String s = getString(id).trim(); |
226 | if (s.length() > 0) { | |
227 | return s.charAt(0); | |
228 | } | |
229 | ||
62c9ec78 NR |
230 | return null; |
231 | } | |
232 | ||
233 | /** | |
234 | * Return the value associated to the given id as a {@link Character}. | |
235 | * | |
236 | * @param mame | |
237 | * the id of the value to get | |
238 | * @param def | |
239 | * the default value when it is not present in the config file or | |
240 | * if it is not a char value | |
241 | * | |
242 | * @return the associated value | |
243 | */ | |
244 | public char getCharacter(E id, char def) { | |
245 | String s = getString(id).trim(); | |
246 | if (s.length() > 0) { | |
247 | return s.charAt(0); | |
248 | } | |
249 | ||
250 | return def; | |
ec1f3444 NR |
251 | } |
252 | ||
b3aad1f9 NR |
253 | /** |
254 | * Return the value associated to the given id as a {@link Color}. | |
255 | * | |
256 | * @param the | |
257 | * id of the value to get | |
258 | * | |
259 | * @return the associated value | |
260 | */ | |
261 | public Color getColor(E id) { | |
262 | Color color = null; | |
263 | ||
264 | String bg = getString(id).trim(); | |
62c9ec78 | 265 | if (bg.startsWith("#") && (bg.length() == 7 || bg.length() == 9)) { |
b3aad1f9 | 266 | try { |
62c9ec78 NR |
267 | int r = Integer.parseInt(bg.substring(1, 3), 16); |
268 | int g = Integer.parseInt(bg.substring(3, 5), 16); | |
269 | int b = Integer.parseInt(bg.substring(5, 7), 16); | |
270 | int a = 255; | |
271 | if (bg.length() == 9) { | |
272 | a = Integer.parseInt(bg.substring(7, 9), 16); | |
273 | } | |
274 | color = new Color(r, g, b, a); | |
b3aad1f9 NR |
275 | } catch (NumberFormatException e) { |
276 | color = null; // no changes | |
277 | } | |
278 | } | |
279 | ||
280 | return color; | |
281 | } | |
282 | ||
62c9ec78 NR |
283 | /** |
284 | * Set the value associated to the given id as a {@link Color}. | |
285 | * | |
286 | * @param the | |
287 | * id of the value to get | |
288 | * | |
289 | * @return the associated value | |
290 | */ | |
291 | public void setColor(E id, Color color) { | |
292 | String r = Integer.toString(color.getRed(), 16); | |
293 | String g = Integer.toString(color.getGreen(), 16); | |
294 | String b = Integer.toString(color.getBlue(), 16); | |
295 | String a = ""; | |
296 | if (color.getAlpha() < 255) { | |
297 | a = Integer.toString(color.getAlpha(), 16); | |
298 | } | |
299 | ||
300 | setString(id, "#" + r + g + b + a); | |
301 | } | |
302 | ||
487926f7 NR |
303 | /** |
304 | * Create/update the .properties file. | |
305 | * <p> | |
306 | * Will use the most likely candidate as base if the file does not already | |
307 | * exists and this resource is translatable (for instance, "en_US" will use | |
308 | * "en" as a base if the resource is a translation file). | |
309 | * <p> | |
310 | * Will update the files in {@link Bundles#getDirectory()}; it <b>MUST</b> | |
311 | * be set. | |
312 | * | |
313 | * @throws IOException | |
314 | * in case of IO errors | |
315 | */ | |
316 | public void updateFile() throws IOException { | |
317 | updateFile(Bundles.getDirectory()); | |
318 | } | |
319 | ||
ec1f3444 | 320 | /** |
80383c14 NR |
321 | * Create/update the .properties file. |
322 | * <p> | |
323 | * Will use the most likely candidate as base if the file does not already | |
324 | * exists and this resource is translatable (for instance, "en_US" will use | |
325 | * "en" as a base if the resource is a translation file). | |
ec1f3444 NR |
326 | * |
327 | * @param path | |
487926f7 NR |
328 | * the path where the .properties files are, <b>MUST NOT</b> be |
329 | * NULL | |
ec1f3444 NR |
330 | * |
331 | * @throws IOException | |
332 | * in case of IO errors | |
333 | */ | |
334 | public void updateFile(String path) throws IOException { | |
335 | File file = getUpdateFile(path); | |
336 | ||
337 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( | |
338 | new FileOutputStream(file), "UTF-8")); | |
339 | ||
340 | writeHeader(writer); | |
341 | writer.write("\n"); | |
342 | writer.write("\n"); | |
343 | ||
344 | for (Field field : type.getDeclaredFields()) { | |
345 | Meta meta = field.getAnnotation(Meta.class); | |
346 | if (meta != null) { | |
347 | E id = E.valueOf(type, field.getName()); | |
348 | String info = getMetaInfo(meta); | |
349 | ||
350 | if (info != null) { | |
351 | writer.write(info); | |
352 | writer.write("\n"); | |
353 | } | |
354 | ||
355 | writeValue(writer, id); | |
356 | } | |
357 | } | |
358 | ||
359 | writer.close(); | |
360 | } | |
361 | ||
80383c14 NR |
362 | /** |
363 | * Reload the {@link Bundle} data files. | |
e9ca6bb8 NR |
364 | * |
365 | * @param resetToDefault | |
366 | * reset to the default configuration (do not look into the | |
367 | * possible user configuration files, only take the original | |
368 | * configuration) | |
80383c14 | 369 | */ |
e9ca6bb8 | 370 | public void reload(boolean resetToDefault) { |
487926f7 | 371 | setBundle(name, Locale.getDefault(), resetToDefault); |
80383c14 NR |
372 | } |
373 | ||
ec1f3444 NR |
374 | /** |
375 | * Check if the internal map contains the given key. | |
376 | * | |
377 | * @param key | |
378 | * the key to check for | |
379 | * | |
380 | * @return true if it does | |
381 | */ | |
382 | protected boolean containsKey(String key) { | |
487926f7 | 383 | return changeMap.containsKey(key) || map.containsKey(key); |
ec1f3444 NR |
384 | } |
385 | ||
386 | /** | |
2cce3dcb NR |
387 | * Get the value for the given key if it exists in the internal map, or NULL |
388 | * if not. | |
ec1f3444 NR |
389 | * |
390 | * @param key | |
391 | * the key to check for | |
392 | * | |
2cce3dcb | 393 | * @return the value, or NULL |
ec1f3444 NR |
394 | */ |
395 | protected String getString(String key) { | |
62c9ec78 NR |
396 | if (changeMap.containsKey(key)) { |
397 | return changeMap.get(key); | |
398 | } | |
399 | ||
487926f7 NR |
400 | if (map.containsKey(key)) { |
401 | return map.get(key); | |
ec1f3444 NR |
402 | } |
403 | ||
404 | return null; | |
405 | } | |
406 | ||
62c9ec78 NR |
407 | /** |
408 | * Set the value for this key, in the change map (it is kept in memory, not | |
409 | * yet on disk). | |
410 | * | |
411 | * @param key | |
412 | * the key | |
413 | * @param value | |
414 | * the associated value | |
415 | */ | |
416 | protected void setString(String key, String value) { | |
487926f7 | 417 | changeMap.put(key, value == null ? null : value.trim()); |
62c9ec78 NR |
418 | } |
419 | ||
ec1f3444 NR |
420 | /** |
421 | * Return formated, display-able information from the {@link Meta} field | |
422 | * given. Each line will always starts with a "#" character. | |
423 | * | |
424 | * @param meta | |
425 | * the {@link Meta} field | |
426 | * | |
427 | * @return the information to display or NULL if none | |
428 | */ | |
429 | protected String getMetaInfo(Meta meta) { | |
430 | String what = meta.what(); | |
431 | String where = meta.where(); | |
432 | String format = meta.format(); | |
433 | String info = meta.info(); | |
434 | ||
435 | int opt = what.length() + where.length() + format.length(); | |
436 | if (opt + info.length() == 0) | |
437 | return null; | |
438 | ||
439 | StringBuilder builder = new StringBuilder(); | |
440 | builder.append("# "); | |
441 | ||
442 | if (opt > 0) { | |
443 | builder.append("("); | |
444 | if (what.length() > 0) { | |
445 | builder.append("WHAT: " + what); | |
446 | if (where.length() + format.length() > 0) | |
447 | builder.append(", "); | |
448 | } | |
449 | ||
450 | if (where.length() > 0) { | |
451 | builder.append("WHERE: " + where); | |
452 | if (format.length() > 0) | |
453 | builder.append(", "); | |
454 | } | |
455 | ||
456 | if (format.length() > 0) { | |
457 | builder.append("FORMAT: " + format); | |
458 | } | |
459 | ||
460 | builder.append(")"); | |
461 | if (info.length() > 0) { | |
462 | builder.append("\n# "); | |
463 | } | |
464 | } | |
465 | ||
466 | builder.append(info); | |
467 | ||
468 | return builder.toString(); | |
469 | } | |
470 | ||
471 | /** | |
472 | * The display name used in the <tt>.properties file</tt>. | |
473 | * | |
474 | * @return the name | |
475 | */ | |
476 | protected String getBundleDisplayName() { | |
477 | return name.toString(); | |
478 | } | |
479 | ||
480 | /** | |
481 | * Write the header found in the configuration <tt>.properties</tt> file of | |
482 | * this {@link Bundles}. | |
483 | * | |
484 | * @param writer | |
485 | * the {@link Writer} to write the header in | |
486 | * | |
487 | * @throws IOException | |
488 | * in case of IO error | |
489 | */ | |
490 | protected void writeHeader(Writer writer) throws IOException { | |
491 | writer.write("# " + getBundleDisplayName() + "\n"); | |
492 | writer.write("#\n"); | |
493 | } | |
494 | ||
495 | /** | |
496 | * Write the given id to the config file, i.e., "MY_ID = my_curent_value" | |
497 | * followed by a new line | |
498 | * | |
499 | * @param writer | |
500 | * the {@link Writer} to write into | |
501 | * @param id | |
502 | * the id to write | |
503 | * | |
504 | * @throws IOException | |
505 | * in case of IO error | |
506 | */ | |
507 | protected void writeValue(Writer writer, E id) throws IOException { | |
508 | writeValue(writer, id.name(), getString(id)); | |
509 | } | |
510 | ||
511 | /** | |
512 | * Write the given data to the config file, i.e., "MY_ID = my_curent_value" | |
513 | * followed by a new line | |
514 | * | |
515 | * @param writer | |
516 | * the {@link Writer} to write into | |
517 | * @param id | |
518 | * the id to write | |
519 | * @param value | |
520 | * the id's value | |
521 | * | |
522 | * @throws IOException | |
523 | * in case of IO error | |
524 | */ | |
525 | protected void writeValue(Writer writer, String id, String value) | |
526 | throws IOException { | |
527 | writer.write(id); | |
528 | writer.write(" = "); | |
529 | ||
530 | if (value == null) { | |
531 | value = ""; | |
532 | } | |
533 | ||
009196a4 | 534 | String[] lines = value.replaceAll("\t", "\\\\\\t").split("\n"); |
ec1f3444 NR |
535 | for (int i = 0; i < lines.length; i++) { |
536 | writer.write(lines[i]); | |
537 | if (i < lines.length - 1) { | |
538 | writer.write("\\n\\"); | |
539 | } | |
540 | writer.write("\n"); | |
541 | } | |
542 | } | |
543 | ||
544 | /** | |
545 | * Return the source file for this {@link Bundles} from the given path. | |
546 | * | |
547 | * @param path | |
548 | * the path where the .properties files are | |
549 | * | |
550 | * @return the source {@link File} | |
551 | * | |
552 | * @throws IOException | |
553 | * in case of IO errors | |
554 | */ | |
555 | protected File getUpdateFile(String path) { | |
556 | return new File(path, name.name() + ".properties"); | |
557 | } | |
558 | ||
559 | /** | |
62c9ec78 | 560 | * Change the currently used bundle, and reset all changes. |
ec1f3444 NR |
561 | * |
562 | * @param name | |
563 | * the name of the bundle to load | |
564 | * @param locale | |
565 | * the {@link Locale} to use | |
e9ca6bb8 NR |
566 | * @param resetToDefault |
567 | * reset to the default configuration (do not look into the | |
568 | * possible user configuration files, only take the original | |
569 | * configuration) | |
ec1f3444 | 570 | */ |
e9ca6bb8 | 571 | protected void setBundle(Enum<?> name, Locale locale, boolean resetToDefault) { |
62c9ec78 | 572 | changeMap.clear(); |
ec1f3444 NR |
573 | String dir = Bundles.getDirectory(); |
574 | ||
487926f7 | 575 | boolean found = false; |
e9ca6bb8 | 576 | if (!resetToDefault && dir != null) { |
ec1f3444 NR |
577 | try { |
578 | File file = getPropertyFile(dir, name.name(), locale); | |
579 | if (file != null) { | |
580 | Reader reader = new InputStreamReader(new FileInputStream( | |
581 | file), "UTF8"); | |
487926f7 NR |
582 | resetMap(new PropertyResourceBundle(reader)); |
583 | found = true; | |
ec1f3444 NR |
584 | } |
585 | } catch (IOException e) { | |
586 | e.printStackTrace(); | |
587 | } | |
588 | } | |
589 | ||
487926f7 NR |
590 | if (!found) { |
591 | String bname = type.getPackage().getName() + "." + name.name(); | |
e9ca6bb8 | 592 | try { |
487926f7 NR |
593 | resetMap(ResourceBundle |
594 | .getBundle(bname, locale, type.getClassLoader(), | |
595 | new FixedResourceBundleControl())); | |
e9ca6bb8 NR |
596 | } catch (Exception e) { |
597 | // We have no bundle for this Bundle | |
487926f7 NR |
598 | System.err.println("No bundle found for: " + bname); |
599 | resetMap(null); | |
600 | } | |
601 | } | |
602 | } | |
603 | ||
604 | /** | |
605 | * Reset the backing map to the content of the given bundle, or empty if | |
606 | * bundle is NULL. | |
607 | * | |
608 | * @param bundle | |
609 | * the bundle to copy | |
610 | */ | |
611 | private void resetMap(ResourceBundle bundle) { | |
612 | this.map.clear(); | |
613 | ||
614 | if (bundle != null) { | |
615 | for (E field : type.getEnumConstants()) { | |
616 | try { | |
617 | String value = bundle.getString(field.name()); | |
618 | this.map.put(field.name(), | |
619 | value == null ? null : value.trim()); | |
620 | } catch (MissingResourceException e) { | |
621 | } | |
e9ca6bb8 NR |
622 | } |
623 | } | |
624 | } | |
625 | ||
626 | /** | |
627 | * Take a snapshot of the changes in memory in this {@link Bundle} made by | |
628 | * the "set" methods ( {@link Bundle#setString(Enum, String)}...) at the | |
629 | * current time. | |
630 | * | |
487926f7 | 631 | * @return a snapshot to use with {@link Bundle#restoreSnapshot(Object)} |
e9ca6bb8 | 632 | */ |
487926f7 | 633 | public Object takeSnapshot() { |
e9ca6bb8 NR |
634 | return new HashMap<String, String>(changeMap); |
635 | } | |
636 | ||
637 | /** | |
638 | * Restore a snapshot taken with {@link Bundle}, or reset the current | |
639 | * changes if the snapshot is NULL. | |
640 | * | |
641 | * @param snap | |
642 | * the snapshot or NULL | |
643 | */ | |
644 | @SuppressWarnings("unchecked") | |
487926f7 | 645 | public void restoreSnapshot(Object snap) { |
e9ca6bb8 NR |
646 | if (snap == null) { |
647 | changeMap.clear(); | |
648 | } else { | |
649 | if (snap instanceof Map) { | |
650 | changeMap = (Map<String, String>) snap; | |
651 | } else { | |
652 | throw new Error( | |
653 | "Restoring changes in a Bundle must be done on a changes snapshot, " | |
654 | + "or NULL to discard current changes"); | |
655 | } | |
ec1f3444 NR |
656 | } |
657 | } | |
658 | ||
659 | /** | |
660 | * Return the resource file that is closer to the {@link Locale}. | |
661 | * | |
662 | * @param dir | |
663 | * the dirctory to look into | |
664 | * @param name | |
665 | * the file basename (without <tt>.properties</tt>) | |
666 | * @param locale | |
667 | * the {@link Locale} | |
668 | * | |
669 | * @return the closest match or NULL if none | |
670 | */ | |
671 | private File getPropertyFile(String dir, String name, Locale locale) { | |
672 | List<String> locales = new ArrayList<String>(); | |
673 | if (locale != null) { | |
674 | String country = locale.getCountry() == null ? "" : locale | |
675 | .getCountry(); | |
676 | String language = locale.getLanguage() == null ? "" : locale | |
677 | .getLanguage(); | |
678 | if (!language.isEmpty() && !country.isEmpty()) { | |
679 | locales.add("_" + language + "-" + country); | |
680 | } | |
681 | if (!language.isEmpty()) { | |
682 | locales.add("_" + language); | |
683 | } | |
684 | } | |
685 | ||
686 | locales.add(""); | |
687 | ||
688 | File file = null; | |
689 | for (String loc : locales) { | |
690 | file = new File(dir, name + loc + ".properties"); | |
691 | if (file.exists()) { | |
692 | break; | |
693 | } else { | |
694 | file = null; | |
695 | } | |
696 | } | |
697 | ||
698 | return file; | |
699 | } | |
700 | } |