Uploaded image for project: 'Errai'
  1. Errai
  2. ERRAI-1101

TranslationService not compatible with GWT ClientBundleGenerator (fallback for untranslated keys doesn't work)

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open (View Workflow)
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: ErraiUI
    • Labels:
      None

      Description

      As reported in RHDM-390, default (English) translation is not displayed when translation for the current non-default locale is missing. This only happens with code using org.jboss.errai.ui.client.local.spi.TranslationService and if the current locale was active during GWT module compilation.

      What I have observed is that TranslationService works for all locales that are part of the resource bundle no matter which locales were active during GWT compilation. The fallback mechanism works unless the locale was added to the locale property in GWT module. For example:

      $ ls -1 optaplanner-wb-solver-editor-client/src/main/resources/org/optaplanner/workbench/screens/solver/client/resources/i18n/
      SolverEditorConstants_de.properties
      SolverEditorConstants_es.properties
      SolverEditorConstants_fr.properties
      SolverEditorConstants_ja.properties
      SolverEditorConstants.properties
      SolverEditorConstants_pt_BR.properties
      SolverEditorConstants_zh_CN.properties
      SolverEditorLookupConstants.properties
       
      $ grep property kie-wb-webapp/src/main/resources/org/kie/workbench/KIEWebapp.gwt.xml 
        <extend-property name="locale" values="es"/>
        <collapse-property name="locale" values="*"/>
        <set-property name="user.agent" value="gecko1_8,safari"/>
        <set-property name="errai.i18n.default_per_key" value="true"/>
      

      SolverEditorConstants.properties has 50 keys, other resources in the bundle only have 3 translated keys. The locale property is extended with a single value "es" so it results in locale="default,es". In this case TranslationService displays the 3 translated texts for all locales and it displays untranslated English text for the remaining 47 keys for all locales excluding ES locale. For ES locale an empty string is returned for each untranslated key.

      The TranslationServiceImpl contains an inner interface for each locale of the bundle:

      public class TranslationServiceImpl extends TranslationService {
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_de_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_de.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_es_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_es.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_fr_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_fr.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_ja_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_ja.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_pt_BR_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_pt_BR.properties") public TextResource getContents(); }
        public interface org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_zh_CN_properties extends MessageBundle, ClientBundle { @Source("org/optaplanner/workbench/screens/solver/client/resources/i18n/SolverEditorConstants_zh_CN.properties") public TextResource getContents(); }
        public TranslationServiceImpl() {
          // get SolverEditorConstants_properties instance and register it for null (default) locale
          org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_properties var32 = GWT.create(org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_properties.class);
          registerPropertiesBundle(var32.getContents().getText(), null);
       
          // get SolverEditorConstants_es_properties instance and register it for ES locale
          org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_es_properties var41 = GWT.create(org_optaplanner_workbench_screens_solver_client_resources_i18n_SolverEditorConstants_es_properties.class);
          registerPropertiesBundle(var41.getContents().getText(), "es");
        }
      }
      

      Observation

      In browser runtime, GWT.create() is "smart" and returns the ClientBundle implementation matching the current locale (and based on the resource path in @Source annotation). Such locale-specific implementations are created by GWT during compilation for all interfaces (even for those interfaces that are intended to be locale-specific). So there are obviously some extra implementations:

      SolverEditorConstants_de_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_de_properties {
      SolverEditorConstants_de_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_de_properties {
       
      SolverEditorConstants_es_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_es_properties {
                            ^^            ^^^^^^^
                interface name            generated by gwt-user because locale always contains "default" value
       
      SolverEditorConstants_es_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_es_properties {
                            ^^            ^^
                interface name            generated by gwt-user because <extend-property name="locale" values="es"/>
       
      SolverEditorConstants_fr_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_fr_properties {
      SolverEditorConstants_fr_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_fr_properties {
      SolverEditorConstants_ja_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_ja_properties {
      SolverEditorConstants_ja_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_ja_properties {
       
      SolverEditorConstants_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_properties {
                           ^           ^^^^^^^
              interface name           generated by gwt-user because locale always contains "default" value
       
      SolverEditorConstants_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_properties {
                           ^           ^^
              interface name           generated by gwt-user because <extend-property name="locale" values="es"/>
       
      SolverEditorConstants_pt_BR_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_pt_BR_properties {
      SolverEditorConstants_pt_BR_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_pt_BR_properties {
      SolverEditorConstants_zh_CN_properties_default_InlineClientBundleGenerator.java:implements SolverEditorConstants_zh_CN_properties {
      SolverEditorConstants_zh_CN_properties_es_InlineClientBundleGenerator.java:implements SolverEditorConstants_zh_CN_properties {
                            ^^^^^            ^^
                   interface name            generated by gwt-user because <extend-property name="locale" values="es"/>
      

      Two different cases can be observed in runtime:

      With locale=de query param

      This is the case when using a locale that has a translation in the properties bundle but wasn't added to the locale property in GWT module. UI code that uses TransationService displays German translation and fallback for untranslated keys works. The i18n-ed code that doesn't use TranslationService is displayd in English.

      See what happens in TranslationServiceImpl constructor:

      • SolverEditorConstants_properties_default_InlineClientBundleGenerator is registered for null dictionary. This impl contains English translation so the fallback works.
      • SolverEditorConstants_de_properties_default_InlineClientBundleGenerator is registerd for DE dictionary. This impl contains German translation so the localization works.
      • SolverEditorConstants_es_properties_default_InlineClientBundleGenerator is registered for ES locale but is never used.

      With locale=es query param (runtime)

      This is the case when using a locale that has a translation resource and was added to GWT module's locale property. UI code that doesn't use TransaltionService is displayed in Spanish (and falls back to English). The code that uses Translation service displays Spanish for translated keys but displays empty strings for untranslated keys.

      What happens inside TranslationServiceImpl constructor:

      • SolverEditorConstants_properties_es_InlineClientBundleGenerator is registered for null dictionary (this is where the smart GWT.create() makes trouble). This impl contains Spanish translation so the fallback doesn't work.
      • SolverEditorConstants_de_properties_es_InlineClientBundleGenerator is registered for DE dictionary. Contains German translation but is never used.
      • SolverEditorConstants_es_properties_es_InlineClientBundleGenerator is registered for ES dictionary. It contains Spanish translation so localization works.

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  mbarkley Max Barkley
                  Reporter:
                  jlocker Jiri Locker
                • Votes:
                  1 Vote for this issue
                  Watchers:
                  2 Start watching this issue

                  Dates

                  • Created:
                    Updated: