Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockoutjs - Can I use data-bind attr together with i18n?

I'm modifying a template in magento2, which have this chunk of code:

<a href="#"
   class="item-action action-gift"
   data-bind="
   attr: {title: 'Gift Options'}
   ">
    <span data-bind="i18n: 'Gift options'"></span>
</a>

I want to be able to translate the title attribute like so

<a href="#"
   class="item-action action-gift"
   data-bind="
   attr: {title: i18n:'Gift Options'}
   ">
    <span data-bind="i18n: 'Gift options'"></span>
</a>

But that obviously gives error. Is it possible to have i18n in the attr binding? How to do it properly if it is?

like image 555
zekkai Avatar asked Nov 30 '25 11:11

zekkai


1 Answers

You can create a custom binding handler that calls a default binding by using ko.applyBindingsToNode.

To inject your i18n translation step, you create a ko.pureComputed representation of your settings object inside the init method and call the original attr binding with it.

Say we have a function named i18n that takes a string and returns another string. We'll go from:

attr: { title: "my string" }

To

attr: { title: i18n("my string") }

Here's how we create the computed object that is passed to attr:

ko.bindingHandlers.i18nAttr = {
  init: function(el, va) {
    var translated = ko.pureComputed(function() {
      // Support observable options objects: unwrap
      var options = ko.unwrap(va());

      return Object
        .keys(options)
        .reduce(function(tOptions, k) {
          // Support observable properties: unwrap
          tOptions[k] = i18n(ko.unwrap(options[k]));
          return tOptions;
        }, {});
    });

    return ko.applyBindingsToNode(el, { attr: translated });
  }
};

In a working example: (I created a computed i18n function to support toggling on and off translations/switching languages)

ko.bindingHandlers.i18nAttr = {
  init: function(el, va) {
    var translated = ko.pureComputed(function() {
      var options = ko.unwrap(va());
      var translate = i18n();

      return Object
        .keys(options)
        .reduce(function(tOptions, k) {
          tOptions[k] = translate(ko.unwrap(options[k]));
          return tOptions;
        }, {});
    });

    return ko.applyBindingsToNode(el, { attr: translated });
  }
};

var translate = ko.observable(true);
var i18n = translater(translate);

var vm = {
  title: "Elevator",
  placeholder: "Cookie",
  translate: translate
};

ko.applyBindings(vm);


// Mock i18n method
function translater(doTranslate) {
  return ko.pureComputed(function() {
    return doTranslate() 
      ? function(str) { return str; }
      : function(str) {
          return ({
            "Elevator": "Lift",
            "Cookie": "Biscuit"
          })[str];
        };
  });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<input data-bind="i18nAttr: { placeholder: placeholder }"/>
<a data-bind="i18nAttr: { title: title }">hover for title</a>

<label><input type="checkbox" data-bind="checked: translate">Translate</label>
like image 93
user3297291 Avatar answered Dec 03 '25 09:12

user3297291



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!