tflori / angular-translator

translation module for angular
https://tflori.github.io/angular-translator/
MIT License
21 stars 6 forks source link

Ability to get whole object #58

Closed BorntraegerMarc closed 7 years ago

BorntraegerMarc commented 7 years ago

I have a translate object like:

{
    "date": {
        "month": {
            "jan": "Januar",
            "feb": "Februar",
            Lots, lots of data
        }
        "weekdays": {
            "sun": "Sonntag",
            "mon": "Montag",
            Lots, lots of data
         }
    even more data
    }
}

Then when calling this.translator.observe(['date.month.jan', 'date.month.feb']) I need to pass every single complete json endpoint

cooler would be if I could only pass: this.translator.observe(['date.month']) and I would get updated over all sub properties

tflori commented 7 years ago

:thinking:

You know already that they get flattened (#4) from json loader. To be able to do this we need to have nested objects in the translation table. This may result in unexpected output when referencing to an object in templates. The output of Translator.instant() will change from string|string[] to string|string[]|object|object[] at least. A loader from .mo files (if someone created such loader) will have to split to objects to use this. In the instant method we need a recursion to get the correct nested object (there is no translations["date.month"] so we try getObject(key.split(.))).

You see there are plenty of changes to achieve this - at least this way. While writing I'm thinking about another solution: instead of returning the key when we don't find it we can search for keys that beginning with this key and return an array or object from them. This will affect only Translator.instant() (which is used by observe and translate) but it will be some bit weird:

> console.log(translator.instant('date.month')); // current: the key
'date.month'
> console.log(translator.instant('date.month')); // your proposal: an object
{ ".jan": "Januar", ".feb": "Februar", "...": "..." }

The current code responsible for this:

if (!this.translations[language] || !this.translations[language][keys[i]]) {
    this.logHandler.info(this.generateMessage("missing", { key: keys[i], language }));
    result.unshift(keys[i]);
    continue;
}

The new code could be something like this:

if (!this.translations[language] || !this.translations[language][keys[i]]) {
    let foundTranslations = this.search(keys[i]+'*', params, language);
    if (Object.keys(foundTranslations).length === 0) {
        this.logHandler.info(this.generateMessage("missing", { key: keys[i], language }));
        result.unshift(keys[i]);
        continue;
    }
    result.unshift(foundTranslations);
    continue;
}
// ...
function search(pattern: string, params: any = {}, language?: string): any {
  let result: any = {};

  language = this.getSelectedLanguage(language);
  if (!language || !this.translations[language]) {
    return result;
  }

  let keys = Object.keys(this.translations[language]).filter((key) => {
    // return (pattern found) ? true : false;
  });

  let i = keys.length;
  let translations = this.instant(keys, params, language);
  while (i--) {
    let k = keys[i].split(pattern).join('');
    result[k] = translations[i];
  }
  return result;
}
BorntraegerMarc commented 7 years ago

Uuups yeah time flies and you forget old issues 😅 Then with the new solution we could get the whole object with translator.instant('date.month'). Sounds perfect! Search function makes sense to me

tflori commented 7 years ago

I'll implement it in the next days then.

tflori commented 7 years ago

will be released with version 2.3 thanks for your contribution