PolymerElements / app-localize-behavior

Polymer behaviour to help internationalize your application
48 stars 54 forks source link

How can i use Localize in ready Function ? #57

Open Naehs opened 8 years ago

Naehs commented 8 years ago

Hi :)

Localization behavior is working fine for me, but i don't know if i can use it in a ready function and how. For exemple, for a login form, i want to show a toast with different informations in two language.

If login are good : {{localize('login_succeeded', 'pseudo', event.detail.response.pseudo)}} If login are wrong : {{localize('login_failed')}} If error : {{localize('login_error')}}

My code :

<div class="container flex-center-justified flex-center-align">
      <div class="inner-container">
        <img src="../images/myApp.png" alt="myApp">
        <h2>myApp</h2>
        <form is="iron-form" method="post" action="../API/v1/index.php/login" id="loginForm">
          <paper-input type="text" name="pseudo" label="{{localize('login_pseudo')}}" no-label-float required></paper-input>
          <paper-input type="password" name="password" label="{{localize('login_password')}}" no-label-float required></paper-input>
          <paper-button noink on-tap="_submit">{{localize('login_submit')}}</paper-button>
          <div class="output"></div>
        </form>
      </div>
    </div>
    <paper-toast id="toast"></paper-toast>
  </template>

  <script>
    Polymer({
      is: 'my-login',

      behaviors: [
        Polymer.AppLocalizeBehavior
      ],

      properties: {
        language: {
          value: 'fr',
          type: String
        }
      },

      attached: function() {
        this.loadResources(this.resolveUrl('locales.json'));
      },

      ready: function() {
        var loginForm = this.$.loginForm;
        var request = loginForm.request;
        var toast = this.$.toast;

        loginForm.addEventListener('iron-form-response', function(event) {
          console.log("Form Error: ",event.detail.response.error);
          if (event.detail.response.error) {
            message = localize('login_failed');
            toast.show({text: message, duration: 5000});
          } else {
            message = localize('login_succeeded', 'pseudo', event.detail.response.pseudo);
            toast.show({text: message, duration: 5000});
          }
        });

        loginForm.addEventListener('iron-form-error', function(event) {
          message = localize('login_error');
          toast.show({text: message, duration: 5000});
        });
      },

      _submit(event) {
        Polymer.dom(event).localTarget.parentElement.submit();
      }
    });
  </script>

locales.json

{
  "en": {
    "login_succeeded": "Greetings {pseudo} !",
    "login_failed": "Incorrect IDs.",
    "login_error": "Oops, an error occurred !",
    "login_pseudo": "Nickname",
    "login_password": "Password",
    "login_submit": "Connection"
  },
  "fr": {
    "login_succeeded": "Salutations {pseudo} !",
    "login_failed": "Identifiants incorrects.",
    "login_error": "Oups, une erreur est survenue !",
    "login_pseudo": "Surnom",
    "login_password": "Mot de passe",
    "login_submit": "Connexion"
  }
}

Thanks. Greetings Loïc.

davebaol commented 7 years ago

I think it should be this.localize('login_failed'), not just localize('login_failed'). However I got it working from inside regular functions only, not from inside lifecycle functions like ready or even attached. Not sure why, though. Maybe this has something to do with computed properties.

hyyan commented 7 years ago

You can use it like that:


this.async(function(){
    this.localize('translation')
},100);
davebaol commented 7 years ago

@hyyan Thanks, this looks like an acceptable solution most of the times. However it's still not clear why computed functions are not available in lifecycle functions. It seems that Polymer documentation is lacking on this topic. :disappointed:

Naehs commented 7 years ago

Thanks guys !

I will try it later. In the case where i want to call a function inside the ready function or a normal function, how it's work ?

For example : See the showToast() function

<script>
 Polymer({
   is: 'my-login',

   ready: function() {
     this.async(function() {
       this.showToast("This is a message...");
     },100);
   },

   otherFunction: function() {
     this.showToast("This is a message...");
   },

   showToast: function(message) {
     toast.show({text: message, duration: 5000});
   }
 });
</script>

Thanks, Loïc.

davebaol commented 7 years ago

Just replace the text message with this.localize('myKey'); Also, about the function you're passing to async, you should either bind it to this or make it an arrow function.

Naehs commented 7 years ago

Hi guys !

I tried this after your recommendation :

toastMessage.show({horizontalAlign: 'right', verticalAlign: 'top', duration: 5000, text: this.async(function() { this.localize('login_failed'); },100)});

And I still have :

Uncaught ReferenceError: this.localize is not defined(…)

Loïc.

davebaol commented 7 years ago

@SheanYu Try something like this

this.async((function() { 
  toastMessage.show({
    horizontalAlign: 'right',
    verticalAlign: 'top',
    duration: 5000,
    text: this.localize('login_failed')
  });
}).bind(this), 100);
Naehs commented 7 years ago

@davebaol Same error...

Note that i'm in the ready function :

ready: function() {
  ...

  loginForm.addEventListener('iron-form-response', function(event) {
    if (event.detail.response.error) {
      this.async((function() { 
        toastMessage.show({
          horizontalAlign: 'right',
          verticalAlign: 'top',
          duration: 5000,
          text: this.localize('login_failed')
        });
      }).bind(this), 100);
    } else {
      ...
    }
  });

  ...
},
davebaol commented 7 years ago

@SheanYu Actually, that code is executed out of the ready function since it's an event handler. You just have to bind the event handler to this like that (function(event) {...}).bind(this)

Naehs commented 7 years ago

@davebaol

With this :

ready: function() {
  ...

  loginForm.addEventListener('iron-form-response', function(event) {
    if (event.detail.response.error) {
      this.async((function() { 
        toastMessage.show({
          horizontalAlign: 'right',
          verticalAlign: 'top',
          duration: 5000,
          text: this.localize('login_failed')
        });
      }).bind(this), 100);
    } else {
      ...
    }
  }).bind(this);

  ...
},

I got this error :

Uncaught TypeError: Cannot read property 'bind' of undefined(…)

ready  @ my-login.html:165
_invokeBehavior @ polymer-micro.html:455
_doBehavior @ polymer-micro.html:445
_readySelf @ polymer-mini.html:88
_ready @ polymer-mini.html:75
_tryReady @ polymer-mini.html:60
_initFeatures @ polymer.html:4053
createdCallback @ polymer-micro.html:202
window.Polymer @ polymer-micro.html:65
(anonymous function) @ my-login.html:124
davebaol commented 7 years ago

@SheanYu Well, you're binding this to nothing. This should make it work

  loginForm.addEventListener('iron-form-response', (function(event) {
    ...
  }).bind(this));
lluisgener commented 7 years ago

I'm having problems too with localize in the ready event. It says localize is not a function.

The (ugly) async approach works most of the times, but sometimes 100ms is not enough and it fails. I know I can increase the timeout, but I think it would be better to have a solution to make it always work.

I understand that resources may not yet be loaded, but I expect it to be another kind of error...

davebaol commented 7 years ago

I understand that resources may not yet be loaded, but I expect it to be another kind of error...

I don't think it's a matter of resources not loaded yet

lluisgener commented 7 years ago

@davebaol Me neither, I think it has something to do with the computed properties and the way Polymer handles them. But, why not make localize a regular function?

davebaol commented 7 years ago

@lluisgener Because being localize a computed property when language or resources change all [[localize(...)]] are dynamically re-calculated.

lluisgener commented 7 years ago

@davebaol I see. But I guess only bound localizations are re-calculated, not the ones invoked programatically. So maybe a good solution would be to keep the computed property as is, and also have a regular function which should be the recommended in a no-bound usage.

Or make the Polymer team invoke the ready event when computed properties have been initialized, if it's possible...

craPkit commented 7 years ago

It seems you can work around this issue using computed properties, like this:

Polymer({
  properties: {
    errorMessage: {
      type: String,
      computed: '_initErrorMessage(localize)'
    },
  },
  _initErrorMessage: function(localize) {
    return localize('myMsg');
  }
});
Mika83AC commented 7 years ago

So is there even any way of calling localize from within a polymer element, indifferent of in the ready() function or any other element function?

As it is usual to process UI texts in functions, it is necessary to grab translations in the code and then pass it to the UI.

Regards, Michael

lluisgener commented 7 years ago

@Mika83AC look at @craPkit post. It worked flawlessly for me. But you need to tweak a little your code to correctly use computed properties.

Regards.

Mika83AC commented 7 years ago

Hm... sure, this is possible but creates an immense overhead (code size, complexity ...). This is just not possible for larger applications and can't be the solution the Polymer team wants to see.

So I really hope they have another solution for us. :)

lluisgener commented 7 years ago

I think that it's the way to go, because localize is a computed method to be able to change language during execution, and I think the better way to do it is with a calculated method, as it is.

Mika83AC commented 7 years ago

Removed because of completely bullshit, sorry :D

craPkit commented 7 years ago

Doesn't this.localize('translationKey') work outside of ready() anyway?

shaffi commented 6 years ago

I manage to resolve this way

<link rel="import" href="../bower_components/app-localize-behavior/app-localize-behavior.html">

<dom-module id="x-custom">

  <template>
    <span> [[_greetings(name, localize)]]</span>
  </template>

  <script>
    Polymer({

      is: 'x-custom',
      behaviors: [
          Polymer.AppLocalizeBehavior
      ],
      properties: {
        name: String,
        language: { type: String,  value: 'zh-CN' }
      },
      attached: function() {
        this.loadResources(this.resolveUrl('locales.json'));
      },
      _greetings: function(name, localize) {
        return  localize('hello')+ ' ' + name;
      }

    });
  </script>

</dom-module>