| Translations.java |
1 /**
2 * Distribution License:
3 * BibleDesktop is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: Translations.java 1738 2008-01-15 02:56:55Z dmsmith $
21 */
22 package org.crosswire.common.util;
23
24 import java.io.IOException;
25 import java.net.URI;
26 import java.net.URL;
27 import java.util.Locale;
28 import java.util.Map;
29
30 import org.crosswire.common.config.ChoiceFactory;
31
32 /**
33 * Translations provides a list of locales that BibleDesktop has been translated
34 * into.
35 *
36 * @see gnu.lgpl.License for license details.<br>
37 * The copyright to this program is held by it's authors.
38 * @author DM Smith [dmsmith555 at yahoo dot com]
39 */
40 public class Translations {
41 /**
42 * Singleton classes have private constructors.
43 */
44 private Translations() {
45 try {
46 loadSupportedTranslations();
47 PropertyMap props = ResourceUtil.getProperties(getClass());
48 translation = props.get(TRANSLATION_KEY);
49 if (translation == null || translation.length() == 0) {
50 // check for a match against language and country
51 // This pertains to zh_TW and zh_CN
52 for (int i = 0; i < translations.length; i++) {
53 Locale supportedLocale = new Locale(translations[i]);
54 if (supportedLocale.getLanguage().equals(originalLocale.getLanguage()) && supportedLocale.getCountry().equals(originalLocale.getCountry())) {
55 translation = translations[i];
56 return;
57 }
58 }
59
60 // check for a match against just language
61 for (int i = 0; i < translations.length; i++) {
62 Locale supportedLocale = new Locale(translations[i]);
63 if (supportedLocale.getLanguage().equals(originalLocale.getLanguage())) {
64 translation = translations[i];
65 return;
66 }
67 }
68
69 // if we don't have a matching locale then just use the default.
70 translation = DEFAULT_TRANSLATION;
71 }
72 } catch (IOException e) {
73 translation = DEFAULT_TRANSLATION;
74 }
75 }
76
77 /**
78 * All access to Translations is through this single instance.
79 *
80 * @return the singleton instance
81 */
82 public static Translations instance() {
83 return instance;
84 }
85
86 /**
87 * Gets a listing of all the translations that Bible Desktop supports.
88 *
89 * @return an string array of translations in locale friendly names.
90 */
91 public PropertyMap getSupported() {
92 loadSupportedTranslations();
93
94 // I18N(DMS) Collate these according to the current locale, putting the
95 // current locale's locale first.
96 PropertyMap names = new PropertyMap();
97
98 for (int i = 0; i < translations.length; i++) {
99 names.put(translations[i], toString(translations[i]));
100 }
101
102 return names;
103 }
104
105 /**
106 * Get the locale for the current translation.
107 *
108 * @return the translation's locale
109 */
110 public Locale getCurrentLocale() {
111 // If there is no particular translation, then return the default
112 // locale.
113 if (translation == null || DEFAULT_TRANSLATION.equals(translation)) {
114 return DEFAULT_LOCALE;
115 }
116
117 // If the local consists of a language and a country then use both
118 if (translation.indexOf('_') != -1) {
119 String[] locale = StringUtil.split(translation, '_');
120 return new Locale(locale[0], locale[1]);
121 }
122
123 // otherwise just use the country.
124 return new Locale(translation);
125 }
126
127 /**
128 * Get the current translation as a human readable string.
129 *
130 * @return the current translation
131 */
132 public String getCurrent() {
133 return toString(translation);
134 }
135
136 /**
137 * Set the current translation, using human readable string.
138 *
139 * @param newTranslation
140 * the translation to use
141 */
142 public void setCurrent(String newTranslation) {
143 String found = DEFAULT_TRANSLATION;
144 String currentTranslation = "";
145 for (int i = 0; i < translations.length; i++) {
146 String trans = translations[i];
147 currentTranslation = toString(translation);
148
149 if (trans.equals(newTranslation) || currentTranslation.equals(newTranslation)) {
150 found = trans;
151 break;
152 }
153 }
154
155 try {
156 translation = found;
157 PropertyMap props = new PropertyMap();
158 if (!DEFAULT_TRANSLATION.equals(translation)) {
159 props.put(TRANSLATION_KEY, translation);
160 }
161
162 URI outputURI = CWProject.instance().getWritableURI(getClass().getName(), FileUtil.EXTENSION_PROPERTIES);
163 NetUtil.storeProperties(props, outputURI, "BibleDesktop UI Translation");
164 } catch (IOException ex) {
165 log.error("Failed to save BibleDesktop UI Translation", ex);
166 }
167 }
168
169 /**
170 * Set the locale for the program to the one the user has selected. But
171 * don't set it to the default translation, so that the user's actual
172 * locale, is used for Bible book names.
173 *
174 * This only makes sense after config has called setCurrentTranslation.
175 */
176 public void setLocale() {
177 Locale.setDefault(getCurrentLocale());
178 }
179
180 /**
181 * Register this class with the common config engine.
182 */
183 public void register() {
184 ChoiceFactory.getDataMap().put(TRANSLATION_KEY, getSupportedTranslations());
185 }
186
187 /**
188 * Get the current translation as a human readable string.
189 *
190 * @return the current translation
191 */
192 public static String getCurrentTranslation() {
193 return Translations.instance().getCurrent();
194 }
195
196 /**
197 * Set the current translation, using human readable string.
198 *
199 * @param newTranslation
200 * the translation to use
201 */
202 public static void setCurrentTranslation(String newTranslation) {
203 Translations.instance().setCurrent(newTranslation);
204 }
205
206 /**
207 * Gets a listing of all the translations that Bible Desktop supports.
208 *
209 * @return an string array of translations in locale friendly names.
210 */
211 public static Map<String, String> getSupportedTranslations() {
212 return Translations.instance().getSupported();
213 }
214
215 /**
216 * Get a list of the supported translations
217 */
218 private void loadSupportedTranslations() {
219 if (translations == null) {
220 try {
221 URL index = ResourceUtil.getResource(Translations.class, "translations.txt");
222 translations = NetUtil.listByIndexFile(NetUtil.toURI(index));
223 } catch (IOException ex) {
224 translations = new String[0];
225 }
226 }
227 }
228
229 public String toString(String translationCode) {
230 StringBuilder currentTranslation = new StringBuilder(Languages.getLanguageName(translationCode));
231
232 if (translationCode.indexOf('_') != -1) {
233 String[] locale = StringUtil.split(translationCode, '_');
234 currentTranslation.append(", ");
235 currentTranslation.append(Countries.getCountry(locale[1]));
236 }
237
238 return currentTranslation.toString();
239 }
240
241 /**
242 * The key used in config.xml
243 */
244 private static final String TRANSLATION_KEY = "translation-codes";
245
246 /**
247 * The default translation, if the user has not chosen anything else.
248 */
249 public static final String DEFAULT_TRANSLATION = "en";
250
251 /**
252 * The default Locale, it the user has not chosen anything else.
253 */
254 public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
255
256 /**
257 * The translation that BibleDesktop should use.
258 */
259 private String translation;
260
261 /**
262 * List of available translations.
263 */
264 private String[] translations;
265
266 /**
267 * The locale that the program starts with. This needs to precede
268 * "instance."
269 */
270 private static Locale originalLocale = Locale.getDefault();
271
272 private static Translations instance = new Translations();
273
274 /**
275 * The log stream
276 */
277 private static final Logger log = Logger.getLogger(Translations.class);
278 }
279