125075a8bbd8268ca6c2310f2e3b40387132e2ac
1 package be
.nikiroo
.utils
.resources
;
4 import java
.io
.IOException
;
6 import java
.util
.LinkedList
;
8 import java
.util
.Locale
;
9 import java
.util
.regex
.Pattern
;
12 * This class manages a translation-dedicated Bundle.
14 * Two special cases are handled for the used enum:
16 * <li>NULL will always will return an empty {@link String}</li>
17 * <li>DUMMY will return "[DUMMY]" (maybe with a suffix and/or "NOUTF")</li>
22 public class TransBundle
<E
extends Enum
<E
>> extends Bundle
<E
> {
23 private boolean utf
= true;
24 private Locale locale
;
25 private boolean defaultLocale
= false;
28 * Create a translation service with the default language.
31 * a runtime instance of the class of E
33 * the name of the {@link Bundles}
35 public TransBundle(Class
<E
> type
, Enum
<?
> name
) {
41 * Create a translation service for the given language (will fall back to
42 * the default one i not found).
45 * a runtime instance of the class of E
47 * the name of the {@link Bundles}
51 public TransBundle(Class
<E
> type
, Enum
<?
> name
, String language
) {
53 setLanguage(language
);
57 * Translate the given id into user text.
62 * the values to insert instead of the place holders in the
65 * @return the translated text with the given value where required or NULL
66 * if not found (not present in the resource file)
68 public String
getString(E stringId
, Object
... values
) {
69 return getStringX(stringId
, "", values
);
73 * Translate the given id into user text.
78 * the values to insert instead of the place holders in the
81 * @return the translated text with the given value where required or NULL
82 * if not found (not present in the resource file)
84 public String
getStringNOUTF(E stringId
, Object
... values
) {
85 return getStringX(stringId
, "NOUTF", values
);
89 * Translate the given id suffixed with the runtime value "_suffix" (that
90 * is, "_" and suffix) into user text.
95 * the values to insert instead of the place holders in the
100 * @return the translated text with the given value where required or NULL
101 * if not found (not present in the resource file)
103 public String
getStringX(E stringId
, String suffix
, Object
... values
) {
107 String key
= id
.name()
108 + ((suffix
== null || suffix
.isEmpty()) ?
"" : "_"
109 + suffix
.toUpperCase());
112 if (containsKey(key
+ "_NOUTF")) {
117 if ("NULL".equals(id
.name().toUpperCase())) {
119 } else if ("DUMMY".equals(id
.name().toUpperCase())) {
120 result
= "[" + key
.toLowerCase() + "]";
121 } else if (containsKey(key
)) {
122 result
= getString(key
);
127 if (values
!= null && values
.length
> 0 && result
!= null)
128 return String
.format(locale
, result
, values
);
134 * Check if unicode characters should be used.
136 * @return TRUE to allow unicode
138 public boolean isUnicode() {
143 * Allow or disallow unicode characters in the program.
146 * TRUE to allow unuciode, FALSE to only allow ASCII characters
148 public void setUnicode(boolean utf
) {
153 * Return all the languages known by the program.
156 * @return the known language codes
158 public List
<String
> getKnownLanguages() {
159 return getKnownLanguages(name
);
163 * Initialise the translation mappings for the given language.
166 * the language to initialise, in the form "en-GB" or "fr" for
169 private void setLanguage(String language
) {
170 defaultLocale
= (language
== null || language
.length() == 0);
171 locale
= getLocaleFor(language
);
172 setBundle(name
, locale
, false);
176 public void reload(boolean resetToDefault
) {
177 setBundle(name
, locale
, resetToDefault
);
181 public String
getString(E id
) {
182 return getString(id
, (Object
[]) null);
186 * Create/update the .properties files for each supported language and for
187 * the default language.
189 * Note: this method is <b>NOT</b> thread-safe.
192 * the path where the .properties files are
194 * @throws IOException
195 * in case of IO errors
198 public void updateFile(String path
) throws IOException
{
199 String prev
= locale
.getLanguage();
200 Object status
= takeChangesSnapshot();
204 if (prev
.equals(getLocaleFor(null).getLanguage())) {
205 // restore snapshot if default locale = current locale
206 restoreChanges(status
);
208 super.updateFile(path
);
210 for (String lang
: getKnownLanguages()) {
212 if (lang
.equals(prev
)) {
213 restoreChanges(status
);
215 super.updateFile(path
);
219 restoreChanges(status
);
223 protected File
getUpdateFile(String path
) {
224 String code
= locale
.toString();
226 if (!defaultLocale
&& code
.length() > 0) {
227 file
= new File(path
, name
.name() + "_" + code
+ ".properties");
229 // Default properties file:
230 file
= new File(path
, name
.name() + ".properties");
237 protected void writeHeader(Writer writer
) throws IOException
{
238 String code
= locale
.toString();
239 String name
= locale
.getDisplayCountry(locale
);
241 if (name
.length() == 0) {
242 name
= locale
.getDisplayLanguage(locale
);
245 if (name
.length() == 0) {
249 if (code
.length() > 0) {
250 name
= name
+ " (" + code
+ ")";
253 name
= (name
+ " " + getBundleDisplayName()).trim();
255 writer
.write("# " + name
+ " translation file (UTF-8)\n");
256 writer
.write("# \n");
257 writer
.write("# Note that any key can be doubled with a _NOUTF suffix\n");
258 writer
.write("# to use when the NOUTF env variable is set to 1\n");
259 writer
.write("# \n");
260 writer
.write("# Also, the comments always refer to the key below them.\n");
261 writer
.write("# \n");
265 protected void writeValue(Writer writer
, E id
) throws IOException
{
266 super.writeValue(writer
, id
);
268 String name
= id
.name() + "_NOUTF";
269 if (containsKey(name
)) {
270 String value
= getString(name
);
271 writeValue(writer
, name
, value
);
276 * Return the {@link Locale} representing the given language.
279 * the language to initialise, in the form "en-GB" or "fr" for
282 * @return the corresponding {@link Locale} or the default {@link Locale} if
285 static private Locale
getLocaleFor(String language
) {
288 if (language
== null) {
289 locale
= Locale
.getDefault();
291 language
= language
.replaceAll("_", "-");
292 String lang
= language
;
293 String country
= null;
294 if (language
.contains("-")) {
295 lang
= language
.split("-")[0];
296 country
= language
.split("-")[1];
300 locale
= new Locale(lang
, country
);
302 locale
= new Locale(lang
);
309 * Return all the languages known by the program.
312 * the enumeration on which we translate
314 * @return the known language codes
316 static protected List
<String
> getKnownLanguages(Enum
<?
> name
) {
317 List
<String
> resources
= new LinkedList
<String
>();
319 String regex
= ".*" + name
.name() + "[_a-zA-Za]*\\.properties$";
321 for (String res
: TransBundle_ResourceList
.getResources(Pattern
323 String resource
= res
;
324 int index
= resource
.lastIndexOf('/');
325 if (index
>= 0 && index
< (resource
.length() - 1))
326 resource
= resource
.substring(index
+ 1);
327 if (resource
.startsWith(name
.name())) {
328 resource
= resource
.substring(0, resource
.length()
329 - ".properties".length());
330 resource
= resource
.substring(name
.name().length());
331 if (resource
.startsWith("_")) {
332 resource
= resource
.substring(1);
333 resources
.add(resource
);