1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.i18n;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.NodeData;
38 import info.magnolia.cms.util.NodeDataUtil;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.jcr.util.PropertyUtil;
41
42 import java.util.Collection;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.LinkedHashMap;
46 import java.util.Locale;
47 import java.util.Map;
48 import java.util.Set;
49
50 import javax.jcr.Node;
51 import javax.jcr.Property;
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66
67 public abstract class AbstractI18nContentSupport implements I18nContentSupport {
68
69 private static final Logger log = LoggerFactory.getLogger(AbstractI18nContentSupport.class);
70
71
72
73
74 private Locale fallbackLocale = new Locale("en");
75
76
77
78
79 protected Locale defaultLocale;
80
81 private boolean enabled = false;
82
83
84
85
86 private final Map<String, Locale> locales = new LinkedHashMap<String, Locale>();
87
88 @Override
89 public Locale getLocale() {
90 Locale locale = null;
91 if(MgnlContext.getWebContextOrNull() != null){
92 locale = MgnlContext.getAggregationState().getLocale();
93 }
94 if (locale == null) {
95 return fallbackLocale;
96 }
97 return locale;
98 }
99
100 @Override
101 public void setLocale(Locale locale) {
102 MgnlContext.getAggregationState().setLocale(locale);
103 }
104
105 @Override
106 public Locale getFallbackLocale() {
107 return this.fallbackLocale;
108 }
109
110 @Override
111 public void setFallbackLocale(Locale fallbackLocale) {
112 this.fallbackLocale = fallbackLocale;
113 }
114
115
116
117
118
119
120
121
122
123
124 protected Locale getNextLocale(Locale locale) {
125
126 if(StringUtils.isNotEmpty(locale.getCountry())){
127
128 Locale langOnlyLocale = new Locale(locale.getLanguage());
129 if(isLocaleSupported(langOnlyLocale)){
130 return langOnlyLocale;
131 }
132 }
133
134 for (Iterator<Locale> iter = getLocales().iterator(); iter.hasNext();) {
135 Locale otherCountryLocale = iter.next();
136
137 if(locale.getLanguage().equals(otherCountryLocale.getLanguage()) && !locale.equals(otherCountryLocale)){
138 return otherCountryLocale;
139 }
140 }
141 return getFallbackLocale();
142 }
143
144
145
146
147 @Override
148 public Locale determineLocale() {
149 Locale locale;
150
151 locale = onDetermineLocale();
152
153
154 if(locale == null){
155 locale = getDefaultLocale();
156 }
157
158 if(!isLocaleSupported(locale)){
159 locale = getNextLocale(locale);
160 }
161
162
163 if(locale.equals(getFallbackLocale())){
164 locale = getDefaultLocale();
165 }
166 return locale;
167 }
168
169 protected abstract Locale onDetermineLocale();
170
171 protected static Locale determineLocalFromString(String localeStr) {
172 if(StringUtils.isNotEmpty(localeStr)){
173 String[] localeArr = StringUtils.split(localeStr, "_");
174 if(localeArr.length ==1){
175 return new Locale(localeArr[0]);
176 }
177 else if(localeArr.length == 2){
178 return new Locale(localeArr[0],localeArr[1]);
179 }
180 }
181 return null;
182 }
183
184 @Override
185 public String toI18NURI(String uri) {
186 if (!isEnabled()) {
187 return uri;
188 }
189 Locale locale = getLocale();
190 if (isLocaleSupported(locale)) {
191 return toI18NURI(uri, locale);
192 }
193 return uri;
194 }
195
196 protected abstract String toI18NURI(String uri, Locale locale);
197
198
199
200
201 @Override
202 public String toRawURI(String i18nURI) {
203 if (!isEnabled()) {
204 return i18nURI;
205 }
206
207 Locale locale = getLocale();
208 if (isLocaleSupported(locale)) {
209 return toRawURI(i18nURI, locale);
210 }
211 return i18nURI;
212 }
213
214 protected abstract String toRawURI(String i18nURI, Locale locale);
215
216 @Override
217 public NodeData getNodeData(Content node, String name, Locale locale) throws RepositoryException {
218 String nodeDataName = name + "_" + locale;
219 if (node.hasNodeData(nodeDataName)) {
220 return node.getNodeData(nodeDataName);
221 }
222 return null;
223 }
224
225
226
227
228
229 @Override
230 public NodeData getNodeData(Content node, String name) {
231 NodeData nd = null;
232
233 if (isEnabled()) {
234 try {
235
236 Locale locale = getLocale();
237 Set<Locale> checkedLocales = new HashSet<Locale>();
238
239
240 while(locale != null){
241 nd = getNodeData(node, name, locale);
242 if (!isEmpty(nd)) {
243 return nd;
244 }
245 checkedLocales.add(locale);
246 locale = getNextContentLocale(locale, checkedLocales);
247 }
248 }
249 catch (RepositoryException e) {
250 log.error("can't read i18n nodeData " + name + " from node " + node, e);
251 }
252 }
253
254
255 return node.getNodeData(name);
256 }
257
258 @Override
259 public Node getNode(Node node, String name) throws RepositoryException {
260 if (isEnabled()) {
261
262 try {
263
264 Locale locale = getLocale();
265 Set<Locale> checkedLocales = new HashSet<Locale>();
266
267
268 while(locale != null){
269 String localeSpecificChildName = name + "_" + locale;
270 if (node.hasNode(localeSpecificChildName)) {
271 return node.getNode(localeSpecificChildName);
272 }
273 checkedLocales.add(locale);
274 locale = getNextContentLocale(locale, checkedLocales);
275 }
276 }
277 catch (RepositoryException e) {
278 log.error("can't read i18n node " + name + " from node " + node, e);
279 }
280 }
281
282 return node.getNode(name);
283 }
284
285 @Override
286 public boolean hasProperty(Node node, String name) throws RepositoryException {
287 if (!isEnabled()) {
288 return node.hasProperty(name);
289 }
290 try {
291
292 getProperty(node, name);
293 } catch (RepositoryException e) {
294 return false;
295 }
296 return true;
297 }
298
299 @Override
300 public Property getProperty(Node node, String name) throws RepositoryException {
301 if (!isEnabled()) {
302 return node.getProperty(name);
303 }
304 try {
305
306 Locale locale = getLocale();
307 Set<Locale> checkedLocales = new HashSet<Locale>();
308
309
310 while (locale != null) {
311 Property property = getProperty(node, name, locale);
312 if (!isEmpty(property)) {
313 return property;
314 }
315 checkedLocales.add(locale);
316 locale = getNextContentLocale(locale, checkedLocales);
317 }
318 } catch (RepositoryException e) {
319 log.error("can't read i18n nodeData " + name + " from node " + node, e);
320 }
321
322
323 return node.getProperty(name);
324 }
325
326 @Override
327 public Property getProperty(Node node, String name, Locale locale) throws RepositoryException {
328 String propName = name + "_" + locale;
329 if (node.hasProperty(propName)) {
330 return node.getProperty(propName);
331 }
332 return null;
333 }
334
335
336
337
338
339
340 protected Locale getNextContentLocale(Locale locale, Set<Locale> checkedLocales) {
341 if(locale.equals(getFallbackLocale())){
342 return null;
343 }
344 Locale candidate = getNextLocale(locale);
345 if(!checkedLocales.contains(candidate)){
346 return candidate;
347 }
348 return getFallbackLocale();
349 }
350
351 @Override
352 public boolean isEnabled() {
353 return this.enabled;
354 }
355
356 public void setEnabled(boolean enabled) {
357 this.enabled = enabled;
358 }
359
360 @Override
361 public Collection<Locale> getLocales() {
362 return this.locales.values();
363 }
364
365 public void addLocale(LocaleDefinition ld) {
366 if (ld.isEnabled()) {
367 this.locales.put(ld.getId(), ld.getLocale());
368 }
369 }
370
371 protected boolean isLocaleSupported(Locale locale) {
372 return locale != null && locales.containsKey(locale.toString());
373 }
374
375
376
377
378
379
380 @Deprecated
381 protected boolean isEmpty(NodeData nd) {
382 if (nd != null && nd.isExist()) {
383
384 return StringUtils.isEmpty(NodeDataUtil.getValueString(nd));
385 }
386 return true;
387 }
388
389
390
391
392 protected boolean isEmpty(Property nd) {
393 if (nd != null) {
394 return StringUtils.isEmpty(PropertyUtil.getValueString(nd));
395 }
396 return true;
397 }
398
399 public Locale getDefaultLocale() {
400 if(this.defaultLocale == null){
401 return getFallbackLocale();
402 }
403 return this.defaultLocale;
404 }
405
406 public void setDefaultLocale(Locale defaultLocale) {
407 this.defaultLocale = defaultLocale;
408 }
409 }