2

First of all, ember's component helper doesn't help in this case. That would only help if I knew how many components I needed to render, and in what order.

I need to be able to render components based on a string like:
{{user}} has made a bid of {{bid}}, where:

  1. {{user}} and {{bid}} will be replaced with components.
  2. the given string is unknown, with an unknown number of dynamic sections representing components (The components would be passed in with the given string).

If these dynamic sections were helpers, this would be easy - but helpers just don't cut it for certain items in my game.

Ideally I could do something like this:

{{translated-content
  content='{{user}} has made a bid of {{bid}}'
  user=(component 'user-ui')
  bid=(component 'bid-ui') }}

Is this possible with ember?

JeremyTM
  • 593
  • 6
  • 17
  • I'm sorry to say that currently this is not possible. – locks Apr 21 '16 at 11:26
  • What if you just pass user and bid to transleted-content component. There you can use computed properties to fetch them as you like, and render the fetched-user and fetched-bid components based on restructured data from the transleted-content's template. But if you want concrete example you need to provide some conrete code. – lependu Apr 21 '16 at 11:50
  • Not answering your question but if you're looking for an internationalizaction solution for Ember, take a look at [ember-i18n](https://github.com/jamesarosen/ember-i18n), I currently use it in a complex application and works really well. – Terseus Apr 21 '16 at 19:21
  • @terseus I'm actually using ember-i18n, and have tried the above example with their `t` helper. Unless I'm missing something, they do not support what I'm trying to do here. – JeremyTM Apr 22 '16 at 04:20
  • @lependu Yes! This is the same thinking I've had. I've actually just finished writing a component which perfectly handles my ideal example above. I'm just going to do some more testing before posting. – JeremyTM Apr 22 '16 at 04:25

1 Answers1

2

With some help, I've come up with the following component which works with ember-i18n, and ember 1.11 or later.

It could likely be optimised further, but it works nice and fast the way it is.

Create a new component

ember g component t-t

template.hbs

{{#each parts as |part|}}

  {{#if part.isComponent}}
    {{component part.content}}
  {{else}}
    {{part.content}}
  {{/if}}

{{/each}}

component.js

import Ember from 'ember';
const { $ } = Ember;

export default Ember.Component.extend({

  tagName: 'span',

  updateComponents: Ember.on('didReceiveAttrs',function(opts){

    let newAttrs = opts.newAttrs;
    let components = {};

    $.each(newAttrs,(key,val)=>{

      if( key !== 't' && typeof val === 'object' ){
        let keys = Object.keys(val);
        if(keys.length && keys[0].indexOf('COMPONENT_')>=0){
          components[key] = val;
        }
      }

    });

    this.set('_components',components);

  }),

  parts: Ember.computed('_components','t','i18n.locale',function(){

    let attrs = [];
    let components = this.get('_components');
    let componentKeys = Object.keys(components);

    $.each(this.attrs,(key,val)=>{
      if( key !== 't'){
        if( componentKeys.indexOf(key)<0 ){
          attrs[key] = val;
        } else {
          attrs[key] = `{{${key}}}`;
        }
      }
    });

    let content = this.get('i18n').t(this.get('t'),attrs).toString();
    content = content.replace(/\{\{(\w+?)\}\}/g,(fullMatch)=>{
      return `{{split}}${fullMatch}{{split}}`;
    });

    let parts = content.split('{{split}}');

    parts.forEach((val,i)=>{
      let isComponent;
      let key = val.replace(/\{\{(\w+?)\}\}/g,(fullMatch,key)=>{
        isComponent = true;
        return key;
      });

      if(isComponent && components[key]){
        parts[i] = {
          isComponent: true,
          content: components[key]
        };
      } else {
        parts[i] = {
          content: Ember.String.htmlSafe(val)
        };
      }

    });

    return parts;

  }),

}).reopenClass({
  positionalParams: ['t']
});

Usage

{{t-t
  'your-ember-i18n-path'
  key1='Normal Content (example)'
  key2=(component 'your-component') }}
JeremyTM
  • 593
  • 6
  • 17