Switching between languages


#1

Hello,

Is there a way to bind value by key? This is the simplified model I have which I’m fetching with Ember Data:

{
  id: 1,
  name: 'page_1',
  content: [{
    name: 'title',
    value: {
      en: 'Home page',
      de: 'Startseite'
    }
  }]
}

Now I want to be able to do something like:

{{#each model.content as |field|}}
  <label>{{field.name}}: {{input type="text" value=field.value[language]}}</label>
{{/each}}

I tried using a custom Handlebars subexpression like so:

{{input type="text" value=(multilingual-value field.value language)}}

But the problem is when the value changes the original model is not updated. Any help is highly appreciated. It is funny how I have built a few mid-sized Ember apps in the past and now I can’t get my head over this…


#2

I don’t know if there is a way of achieving what you want to do but you can create a component wrapping the input and checking the language to know which key it must bind:

//component
{{language-input language=language value=field.value}}

//template
{{#if isEnglish}}
  {{input type="text" value=value.en}}
{{/else}}
  {{input type="text" value=value.de}}
{{/if}}

#3

Yes I thought about that too, but I felt there should be a more elegant way of solving this. I ended up changing data format and added a computed property to controller that filters embedded records by current language. Here’s the idea:

JSON:

{
  id: 1,
  name: 'page_1',
  content: [{
    name: 'title',
    lang: 'en',
    value: 'Home page'
  }, {
    name: 'title',
    lang: 'de',
    value: 'Startseite'
  }]
}

Controller:

export default Ember.Controller.extend({
    queryParams: ['lang'],
    lang: 'lt',

    fieldsInCurrentLang: Ember.computed('model.content.@each.name', 'lang', function() {
        var lang = this.get('lang');        
        return this.get('model.content').filterBy('lang', lang);
    })
});

Handlebars:

{{#link-to 'pages.edit' model (query-params lang='en')}}En{{/link-to}}
{{#link-to 'pages.edit' model (query-params lang='de')}}De{{/link-to}}

{{#each fieldsInCurrentLang as |field|}}
    <label>{{field.name}}: {{input type="text" value=field.value}}</label>
{{/each}}

#4

I don’t know about your user case but what you are trying to do is some kind of internationalization (commonly known as i18n), right? as far as I know, that works a bit different as you are doing now. Instead of having your strings and your translations in the model, you have only keys (or unique strings in a specific language) and then in another part a list of translations for those keys, so you end up looking for the key and the language and showing the right string.


#5

What I’m building is a tool where users can compose a form from a variety of different input fields. Labels for the fields need to be available in several languages. Using a translation map would lead me to the original problem where I was not able to bind value by key. This is what I’d end up with:

{{input type="text" value=translationMap[model.name]}}

I couldn’t find a way to solve this that’s why I went for a different approach.


#6

What I do for content editing in various languages is that the model has every language version as a separate property, like (with ember-data):

App.Animal = DS.Model.extend
  nameEn: DS.attr 'string'
  nameFr: DS.attr 'string'

and controller which is aware of the current locale creates a thin wrapper around it with a virtual property without the language suffix, like so:

App.AnimalController = Admin.ObjectController.extend Admin.UploadMixin,
  needs: [ 'contentLocale' ]
  name: Barbecue.translatedProperty('name')

using this controller as a reference point for locale settings:

Barbecue.ContentLocaleController = Ember.ObjectController.extend
  model: 'fr'
  current: Ember.computed.alias('model')

Then you can write:

{{#each animal in safari itemController='animal' }}
  {{input value=animal.name}}
{{/each}}

and when you change the language the value will correctly switch.

The white magic happens in the computed property generated by the #translatedProperty method. It is both setter and getter. But can be simplified if you don’t need such a general case.

Hope that helps.

Jakub


#7

This is exactly what I needed! Will be updating this post later this evening with my final solution :smile:

{{input type="text" value=(mut (get translation lang))}}

Where translation is an Ember Data model, smth like this:

DS.Model.extend({
  en: DS.attr('string'),
  de: DS.attr('string')
})

#8

This is what I ended up with: