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