Skip to content

tKey

Use tKey to mark strings that you know are actually translation keys. This helps programs (e.g. @ember-intl/lint) check how you use translations.

NOTE

tKey is an identity function. The output string and its type (string or a string literal) are the same as the input.

gts
import Component from '@glimmer/component';
import { t, tKey } from 'ember-intl';

type Option = {
  labelKey: string;
  value: string;
};

interface SelectLocaleSignature {
  Args: {};
}

export default class SelectLocale extends Component<SelectLocaleSignature> {
  get options(): Option[] {
    return [
      {
        labelKey: tKey('select-locale.de-de'),
        value: 'de-de',
      },
      {
        labelKey: tKey('select-locale.en-us'),
        value: 'en-us',
      },
    ];
  }

  <template>
    {{#each this.options as |opt|}}
      <option value={{opt.value}}>
        {{t opt.labelKey}}
      </option>
    {{/each}}
  </template>
}

Here is another example, where translation keys appear in a utility file (a normal *.{js,ts} file).

gts
import { type Registry as Services, service } from '@ember/service';
import Component from '@glimmer/component';
import { PAYMENT_METHOD, TRANSLATION_KEYS } from 'my-app/utils/payment';

type Option = {
  label: string;
  value: string;
};

interface PaymentMethodSignature {
  Args: {};
}

export default class PaymentMethod extends Component<PaymentMethodSignature> {
  @service declare intl: Services['intl'];

  get options(): Option[] {
    return Object.values(PAYMENT_METHOD).map((paymentMethod) => {
      return {
        label: this.intl.t(TRANSLATION_KEYS[paymentMethod]),
        value: paymentMethod,
      };
    });
  }

  <template>
    {{#each this.options as |opt|}}
      <option value={{opt.value}}>
        {{opt.label}}
      </option>
    {{/each}}
  </template>
}
ts
import { tKey } from 'ember-intl';

// Values set by backend
export const PAYMENT_METHOD = {
  BANK_TRANSFER: 'bank_transfer',
  CREDIT_CARD: 'credit_card',
  DIRECT_DEBIT: 'direct_debit',
} as const;

export const TRANSLATION_KEYS = {
  [PAYMENT_METHOD.BANK_TRANSFER]: tKey('payment-method.bank-transfer'),
  [PAYMENT_METHOD.CREDIT_CARD]: tKey('payment-method.credit-card'),
  [PAYMENT_METHOD.DIRECT_DEBIT]: tKey('payment-method.direct-debit'),
} as const;

What to avoid

Don't pass a dynamic expression (code that can easily be determined only at runtime) to tKey. It's difficult and costly for programs to accurately find all possible values.

Refactor code so that you always pass strings or string literals to tKey.

gts
import { concat } from '@ember/helper';
import { t, tKey } from 'ember-intl';

const locales = ['de-de', 'en-us'] as const;

<template>
  {{#each locales as |locale|}}
    <option value={{locale}}>
      {{! ❌ Helpers like `concat` will be ignored }}
      {{t (tKey (concat "select-locale." locale))}}
    </option>
  {{/each}}
</template>
gts
import { get } from '@ember/helper';
import { t, tKey } from 'ember-intl';

const locales = ['de-de', 'en-us'] as const;

const localeToKey = {
  'de-de': tKey('select-locale.de-de'),
  'en-us': tKey('select-locale.en-us'),
} as const;

<template>
  {{#each locales as |locale|}}
    <option value={{locale}}>
      {{t (get localeToKey locale)}}
    </option>
  {{/each}}
</template>
gts
import { array, hash } from '@ember/helper';
import { t, tKey } from 'ember-intl';

<template>
  {{#let
    (array
      (hash labelKey="select-locale.de-de" value="de-de")
      (hash labelKey="select-locale.en-us" value="en-us")
    )
    as |options|
  }}
    {{#each options as |opt|}}
      <option value={{opt.value}}>
        {{! ❌ Path expressions like `opt.labelKey` will be ignored }}
        {{t (tKey opt.labelKey)}}
      </option>
    {{/each}}
  {{/let}}
</template>
gts
import { array, hash } from '@ember/helper';
import { t, tKey } from 'ember-intl';

<template>
  {{#let
    (array
      (hash labelKey=(tKey "select-locale.de-de") value="de-de")
      (hash labelKey=(tKey "select-locale.en-us") value="en-us")
    )
    as |options|
  }}
    {{#each options as |opt|}}
      <option value={{opt.value}}>
        {{t opt.labelKey}}
      </option>
    {{/each}}
  {{/let}}
</template>