Cropster / ember-l10n

A GNU gettext based localization workflow for Ember
MIT License
15 stars 7 forks source link

Question #90

Closed himanshujaidka closed 3 years ago

himanshujaidka commented 3 years ago

Hello, maintainers :) I want a way for strings to be extracted but l10n.t returns translated strings, so is there is any way to modify the library that returns untranslated string but extracts it using CLI?

mydea commented 3 years ago

Not sure I understand the question correctly? You want strings to be picked up for translation when extracting via l10n.t(), but you do not want the outputofl10n.t()` to be actually translated? What is the use case for this?

iamareebjamal commented 3 years ago

For example, I am listing the countries in JS:

const countries = [
  'India',
  'Brazil',
  ...
];

I want this to be translatable, so I use t-var in dropdown.

<UiDropdown @value={{@event.country}} @countries={{this.countries}}>
    <Item>{{t-var country}}</Item>
</UiDropdown>

Now, I show the translated string in the UI, and the value assigned to event.country is untranslated because that should be saved in DB untranslated, all is good.

But now, the strings are not extracted, and I have to duplicate the array like

const t_countries = [
  this.l10n.t('India'),
  this.l10n.t('Brazil'),
  ...
];

Just to extract the strings, and use the old array for actual logic. This could be solved if we had a no-op function which did no translation but only extracted strings, like

const t_countries = [
  this.l10n.tnop('India'),
  this.l10n.tnop('Brazil'),
  ...
];

This extracts India and Brazil, but also returns them untranslated so it effectively becomes

const countries = [
  'India',
  'Brazil',
  ...
];

This could be achieved using --keys argument but it doesn't work. If you understand the use case, I'd be happy to contribute the change as we really need it in our project and cannot achieve the result without duplicating a lot of arrays. Or do you have an alternative in mind?

mydea commented 3 years ago

IMHO the way to go with this is still to provide a manual list, where l10n.t() is invoked. For example, something like this:

export default class CountryListService extends Service {
  @service l10n;

  countryMap; // Set in constructor

  constructor() {
    super(...arguments);
    let { l10n } = this;

    this.countryMap = [
      { name: 'Brazil', label: l10n.t('Brazil') },
      { name: 'India', label: l10n.t('India') }
    ];
  }
}

This is a bit more verbose but much more explicit and less magic.

If you really want to "hack" around this and just make the parser pick it up, you can just provide your "own" .t() function, which will also be picked up by the extractor. E.g.:

export default class CountryListService extends Service {

  l10n = {
    t: (str) => str
  };

  countryMap; // Set in constructor

  constructor() {
    super(...arguments);
    let { l10n } = this;

    this.countryMap = [
      l10n.t('Brazil'),
      l10n.t('India')
    ];
  }
}

The extractor basically picks up any xx.t("my thing") invocations, so that will also work. I would advise you against this pattern, though, and rather err towards always explicitly mapping any enums or similar as in my first example.

iamareebjamal commented 3 years ago

Thank You. First option is not possible when we have a huge list of items, we were already thinking of using the 2nd workaround, thanks for the suggestion

himanshujaidka commented 3 years ago

Thanks, @iamareebjamal sir and @mydea sir