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 }
175 else if(localeArr.length == 2){
176 return new Locale(localeArr[0],localeArr[1]);
177 }
178 }
179 return null;
180 }
181
182 @Override
183 public String toI18NURI(String uri) {
184 if (!isEnabled()) {
185 return uri;
186 }
187 Locale locale = getLocale();
188 if (isLocaleSupported(locale)) {
189 return toI18NURI(uri, locale);
190 }
191 return uri;
192 }
193
194 protected abstract String toI18NURI(String uri, Locale locale);
195
196
197
198
199 @Override
200 public String toRawURI(String i18nURI) {
201 if (!isEnabled()) {
202 return i18nURI;
203 }
204
205 Locale locale = getLocale();
206 if (isLocaleSupported(locale)) {
207 return toRawURI(i18nURI, locale);
208 }
209 return i18nURI;
210 }
211
212 protected abstract String toRawURI(String i18nURI, Locale locale);
213
214 @Override
215 public NodeData getNodeData(Content node, String name, Locale locale) throws RepositoryException {
216 String nodeDataName = name + "_" + locale;
217 if (node.hasNodeData(nodeDataName)) {
218 return node.getNodeData(nodeDataName);
219 }
220 return null;
221 }
222
223
224
225
226
227 @Override
228 public NodeData getNodeData(Content node, String name) {
229 NodeData nd = null;
230
231 if (isEnabled()) {
232 try {
233
234 Locale locale = getLocale();
235 Set<Locale> checkedLocales = new HashSet<Locale>();
236
237
238 while(locale != null){
239 nd = getNodeData(node, name, locale);
240 if (!isEmpty(nd)) {
241 return nd;
242 }
243 checkedLocales.add(locale);
244 locale = getNextContentLocale(locale, checkedLocales);
245 }
246 }
247 catch (RepositoryException e) {
248 log.error("can't read i18n nodeData {} from node {}", name, node, e);
249 }
250 }
251
252
253 return node.getNodeData(name);
254 }
255
256 @Override
257 public Node getNode(Node node, String name) throws RepositoryException {
258 if (isEnabled()) {
259
260 try {
261
262 Locale locale = getLocale();
263 Set<Locale> checkedLocales = new HashSet<Locale>();
264
265
266 while(locale != null){
267 String localeSpecificChildName = name + "_" + locale;
268 if (node.hasNode(localeSpecificChildName)) {
269 return node.getNode(localeSpecificChildName);
270 }
271 checkedLocales.add(locale);
272 locale = getNextContentLocale(locale, checkedLocales);
273 }
274 }
275 catch (RepositoryException e) {
276 log.error("can't read i18n node {} from node {}", name, node, e);
277 }
278 }
279
280 return node.getNode(name);
281 }
282
283 @Override
284 public boolean hasProperty(Node node, String name) throws RepositoryException {
285 if (!isEnabled()) {
286 return node.hasProperty(name);
287 }
288 try {
289
290 getProperty(node, name);
291 } catch (RepositoryException e) {
292 return false;
293 }
294 return true;
295 }
296
297 @Override
298 public Property getProperty(Node node, String name) throws RepositoryException {
299 if (!isEnabled()) {
300 return node.getProperty(name);
301 }
302 try {
303
304 Locale locale = getLocale();
305 Set<Locale> checkedLocales = new HashSet<Locale>();
306
307
308 while (locale != null) {
309 Property property = getProperty(node, name, locale);
310 if (!isEmpty(property)) {
311 return property;
312 } else if (locale.equals(getDefaultLocale()) && node.hasProperty(name)) {
313 return node.getProperty(name);
314 }
315 checkedLocales.add(locale);
316 locale = getNextContentLocale(locale, checkedLocales);
317 }
318 } catch (RepositoryException e) {
319 log.error("can't read i18n property {} from node {}", name, 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 setLocales(Map<String, Locale> locales) {
366 this.locales.putAll(locales);
367 }
368
369 public void addLocale(LocaleDefinition ld) {
370 if (ld.isEnabled()) {
371 this.locales.put(ld.getId(), ld.getLocale());
372 }
373 }
374
375 protected boolean isLocaleSupported(Locale locale) {
376 return locale != null && locales.containsKey(locale.toString());
377 }
378
379
380
381
382
383
384 @Deprecated
385 protected boolean isEmpty(NodeData nd) {
386 if (nd != null && nd.isExist()) {
387
388 return StringUtils.isEmpty(NodeDataUtil.getValueString(nd));
389 }
390 return true;
391 }
392
393
394
395
396 protected boolean isEmpty(Property property) {
397 try {
398 if (property != null) {
399 return (property.isMultiple()) ? property.getValues().length == 0 : StringUtils.isEmpty(PropertyUtil.getValueString(property));
400 }
401 } catch (RepositoryException e) {
402 log.warn("Can't read value from property {}", property, e);
403 }
404 return true;
405 }
406
407 @Override
408 public Locale getDefaultLocale() {
409 if(this.defaultLocale == null){
410 return getFallbackLocale();
411 }
412 return this.defaultLocale;
413 }
414
415 public void setDefaultLocale(Locale defaultLocale) {
416 this.defaultLocale = defaultLocale;
417 }
418 }