View Javadoc

1   /**
2    * This file Copyright (c) 2013 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.i18nsystem.tools;
35  
36  import info.magnolia.cms.i18n.Messages;
37  import info.magnolia.cms.i18n.MessagesManager;
38  import info.magnolia.i18nsystem.I18nKeyGenerator;
39  import info.magnolia.i18nsystem.LocaleProvider;
40  import info.magnolia.i18nsystem.TranslationService;
41  import info.magnolia.i18nsystem.proxytoys.I18nTextMethodDecorator;
42  import info.magnolia.i18nsystem.proxytoys.ProxytoysI18nizer;
43  
44  import java.lang.reflect.Method;
45  import java.util.Locale;
46  
47  import javax.inject.Inject;
48  
49  /**
50   * A {@link info.magnolia.i18nsystem.I18nizer} which keeps track of translation attempts and figures out new/replacement keys (for example if a configured key exists, it can suggest to remove the configuration and replace the key with a generated one).
51   */
52  public class ToolingProxytoysI18nizer extends ProxytoysI18nizer {
53      private final TranslationService translationService;
54      private final LocaleProvider localeProvider;
55      // private final Locale locale;
56      private final GeneratorResults genRes;
57  
58      @Inject
59      public ToolingProxytoysI18nizer(TranslationService translationService, LocaleProvider localeProvider) {
60          super(translationService, localeProvider);
61          this.translationService = translationService;
62          this.genRes = new GeneratorResults(localeProvider.getLocale());
63          this.localeProvider = localeProvider;
64      }
65  
66      /**
67       * For manual invocations - see {@link GenerateTranslationFilesImpl}.
68       */
69      public ToolingProxytoysI18nizer(final GeneratorResults genRes, final Locale locale, final TranslationService translationService) {
70          this(genRes, translationService, new StaticLocaleProvider(locale));
71      }
72  
73      private ToolingProxytoysI18nizer(GeneratorResults genRes, TranslationService translationService, LocaleProvider localeProvider) {
74          super(translationService, localeProvider);
75          this.translationService = translationService;
76          this.localeProvider = localeProvider;
77          this.genRes = genRes;
78      }
79  
80      @Override
81      protected <T> I18nTextMethodDecorator<T> newI18nTextMethodDecorator(final I18nKeyGenerator<T> keyGen) {
82          return new I18nTextMethodDecorator<T>(translationService, localeProvider, keyGen) {
83              @Override
84              protected Object decorate(String undecoratedResult, T proxiedObject, Method method) {
85                  final Object decorated = super.decorate(undecoratedResult, proxiedObject, method);
86                  // two lines below copied from I18nTextMethodDecorator.decorate()
87                  final String[] keys = keyGen.keysFor(undecoratedResult, proxiedObject, method);
88                  final String basenameKG = keyGen.messageBundleNameFor(proxiedObject);
89  
90                  final String theKeyThatShouldBe;
91                  if (keys[0].equals(undecoratedResult)) {
92                      theKeyThatShouldBe = keys[1];
93                  } else {
94                      theKeyThatShouldBe = keys[0];
95                  }
96  
97                  final LegacyMessage legacyMessage = getLegacyMessage(localeProvider.getLocale(), basenameKG, keys);
98                  if (legacyMessage != null) {
99                      // System.out.println("> legacyMessage: " + legacyMessage.key+" ->"+legacyMessage.value);
100                     // System.out.println("legacyMessage[0].equals(keys[0]): " + legacyMessage.key.equals(keys[0]));
101                     // System.out.println(" --> we want new key: "+keys[1]+" and old translation:"+legacyMessage.value);
102                     genRes.add(new GeneratorResult.AddKeyToNewBundle(localeProvider.getLocale(), theKeyThatShouldBe, legacyMessage.value));
103                     genRes.add(new GeneratorResult.RemoveKeyFromLegacyBundle(legacyMessage.basename, legacyMessage.key, /* we don't know the path yet */null));
104 
105                 } else if (undecoratedResult != null && Locale.ENGLISH.equals(localeProvider.getLocale())) {
106                     // we have a configured value, but no translation in the legacy files - assume it's an hard-configured text:
107                     genRes.add(new GeneratorResult.AddKeyToNewBundle(localeProvider.getLocale(), theKeyThatShouldBe, undecoratedResult));
108                 } else {
109                     genRes.add(new GeneratorResult.AddUntranslatedKeyToNewBundle(localeProvider.getLocale(), theKeyThatShouldBe));
110                 }
111 
112                 return decorated;
113             }
114         };
115     }
116 
117     protected LegacyMessage getLegacyMessage(Locale locale, String basename, String[] keys) {
118         for (String key : keys) {
119             LegacyMessage res = getLegacyMessage(locale, basename, key);
120             if (res == null) {
121                 // TODO: try also with default basenames from UI
122                 res = getLegacyMessage(locale, null, key);
123             }
124             if (res != null) {
125                 return res;
126             }
127         }
128         return null;
129     }
130 
131     private LegacyMessage getLegacyMessage(Locale locale, String basename, String key) {
132         final Messages messages = MessagesManager.getMessages(basename, locale);
133         final String s = messages.get(key);
134         return pairOrNull(messages.getBasename(), key, s);
135     }
136 
137     private LegacyMessage pairOrNull(String basename, String key, String s) {
138         if (s != null && !(s.startsWith("???"))) {
139             return new LegacyMessage(basename, key, s);
140         }
141         return null;
142     }
143 
144     /**
145      * LegacyMessage.
146      */
147     static class LegacyMessage {
148         final String basename, key, value;
149 
150         LegacyMessage(String basename, String key, String value) {
151             this.basename = basename;
152             this.key = key;
153             this.value = value;
154         }
155     }
156 
157     private static class StaticLocaleProvider implements LocaleProvider {
158         private final Locale locale;
159 
160         public StaticLocaleProvider(Locale locale) {
161             this.locale = locale;
162         }
163 
164         @Override
165         public Locale getLocale() {
166             return locale;
167         }
168     }
169 }