Search code examples
javascripttypescripttranslate

Lit-translate shows code or key instead of translation


I am trying to use lit-translate to translate my "Elmish" typescript website into different languages. I use webpack and dotnet.

Inside my index.ts I register the translate config:

registerTranslateConfig({
    lookup: (key, config) => config.strings != null ? config.strings[key] : key,
    empty: key => key,
    loader: lang => {
          return new Promise((resolve, reject) => {
            resolve({"title": "Der Titel"});
          })}   
    });

use("en");

(The loader is hardcoded because getting the localization file also didn't work, but that's not important for now).

Inside html I use get("title")or translate("title") to get the translation. Instead of the translation, I either read [title] or (part) => { partCache.set(part, cb); updatePart(part, cb); }

If I assign the result of translate() to a variable, I get the following result inside the Object:

TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
    at Function.r (<anonymous>:1:83)
    at Module../src/index.ts (http://localhost:8080/app.bundle.js:9800:10)
    at __webpack_require__ (http://localhost:8080/app.bundle.js:12476:33)
    at http://localhost:8080/app.bundle.js:13494:11
    at http://localhost:8080/app.bundle.js:13497:12

I already tried disabling webpack strict mode.

The full class looks like the following:

export class App extends Application<Model, Message, {}> {
  @property({type: Boolean})
  hasLoadedStrings = false;

    init(): [Model, Cmd] {
    const initModel: Model = {
      openPage: [{title: "Home"}, home]
    }

    return [initModel, Cmd.none]
  }

  constructor() {
    super();
    this.hasLoadedStrings = false;
  }

  shouldUpdate (changedProperties: Map<string | number | symbol, unknown>) {
    return this.hasLoadedStrings && super.shouldUpdate(changedProperties);
  }

  async connectedCallback () {
    super.connectedCallback();
 
    await use("en");
    this.hasLoadedStrings = true;
  }

}

customElements.define('my-element', App);

Solution

  • I solved the problem by writing my own little translation library. The lit-translate package contains errors if you use it as suggested in the documentation so feel free to use my solution:

    translate.ts:

    const de_config = 
    {
      "Category": {
        "Home": "Start",
      },
      "Home": {
        "Welcome back,": "Willkommen zurück,"
    };
    
    export function translate(key: string) {
    
        const keyParts = key.split(".");
        const keyCategory = keyParts.shift();
        const keyWord = keyParts.join('.');
    
        let translationIndexes = typedKeys(de_config);
    
        for(let translationIndex of translationIndexes)
        {
          if(translationIndex == keyCategory) {
            let translationKeys = typedKeys(de_config[translationIndex]);
            
            for(let translationKey of translationKeys) {
                if(translationKey == keyWord) {
                  return de_config[translationIndex][translationKey];         
              }
            }
          }
        }
        return key;  
      }
    
    function typedKeys<T>(o: T): (keyof T)[] {
        return Object.keys(o) as (keyof T)[];
      }
    

    Access translations with:

    import { translate } from './translate';
    translate("Category.Home");
    

    One could also store translation object in a different file, write a function to change language dynamically, etc...