Gothem
Gothem

Reputation: 381

Angular $localize using dynamic translation ID

With new Angular 9 @angular/localize is now possible to translate code directly from typescript. As its usage is not officially well documented, I found some tips on this post.

$localize`:@@my-trans-unit-id:` // IT WORKS

That works correctly when ID is directly passed to the function, but if I want ID to be dynamic (and pass a variable), it does not work, rendering ID without parsing nor translating.

I tried it by passing the variable this way:

const id = "my-trans-unit-id";

$localize`:@@${id}:`; // NOT WORKING
$localize`:@@`+id+`:`; // NOT WORKING

Upvotes: 11

Views: 6723

Answers (3)

This works.

Don't ask me to explain, I got this by trial and error:

const localize = $localize;
const id = "my-trans-unit-id";
const translation = localize(<any>{ '0': `:@@${id}:${id}`, 'raw': [':'] });

Upvotes: 9

Florian
Florian

Reputation: 547

You can create your own tagged templates function to handle transformation of the trans-unit id:

const transUnitId = '@@Messages.Greeting';
const name = 'Joe';
const message = $localizeId`${transUnitId}:TRANSUNITID:Hi ${name}:NAME:, translated with run-time created trans-unit id.`;
// Original
// message = Hi Joe, translated with run-time created trans-unit id.
// German
// message = Hallo Joe, übersetzt mit einer zur Laufzeit erstellten Trans-Unit-Id.
export function $localizeId(messageParts: TemplateStringsArray, ...expressions: any[]): string {
  // Create writeable copies
  const messagePartsCopy: any = [...messageParts];
  const messagePartsRawCopy = [...messageParts.raw];

  // Strip trans-unit-id element
  const prefix = messagePartsCopy.shift();
  const prefixRaw = messagePartsRawCopy.shift();
  const transUnitId = expressions.shift();

  // Re-add prefix and replace :TRANSUNITID: with transUnitId.
  messagePartsCopy[0] = prefix + messagePartsCopy[0].replace(':TRANSUNITID:', `:@@${transUnitId}:`);
  messagePartsRawCopy[0] = prefixRaw + messagePartsRawCopy[0].replace(':TRANSUNITID:', `:${transUnitId}:`);

  // Create messageParts object
  Object.defineProperty(messagePartsCopy, 'raw', {value: messagePartsRawCopy});

  // Call original localize function
  return $localize(messagePartsCopy as TemplateStringsArray, ...expressions);
}

Upvotes: 1

Gothem
Gothem

Reputation: 381

Angular does not provide any mechanism to generate dynamic translations as they are generated at compile time.

I ended up creating pipes and calling them every time I need a translation. Instead of using 1 unique instruction to translate the string, I use multiple $localize calls inside a switch to return proper translation by ID.

This is an example for translating order status that can be called on runtime:

import { Pipe, PipeTransform } from '@angular/core';
import { OrderStatusEnum } from 'installation-status.enum';

@Pipe({
    name: 'orderStatusRenderer'
})
export class OrderStatusRendererPipe implements PipeTransform {
    constructor() {}

    transform(value: number, ...args: any[]): any {
        switch (value) {
            case OrderStatusEnum.PREPARING:
                return $localize`:@@order.status.preparing:`;
            case OrderStatusEnum.SHIPPED:
                return $localize`:@@order.status.shipped:`;
            case OrderStatusEnum.COMPLETED:
                return $localize`:@@order.status.completed:`;
        }
    }
}

Upvotes: 10

Related Questions