Message formatting

18ways uses waysParser by default. That parser is what lets you keep the source copy readable while still handling variables and locale-aware formatting.

Variables

Dùng dấu ngoặc nhọn cho biến. Với <T>, bạn có thể giữ giá trị nội tuyến ngay cạnh thông báo.

ts
const label = await engine.t('Welcome back, {name}', {
  vars: { name: 'Ada' },
});

Pluralization

Use ICU-style plural blocks when the sentence genuinely changes shape.

ts
const summary = await engine.t(
  '{count, plural, =0{No messages} =1{One message} other{{count} messages}}',
  {
    vars: { count: 3 },
  }
);

Dates and money

If you pass a real Date or a money-like object with amount and currency, 18ways will format it automatically even with a bare placeholder like {publishedAt} or {renewalTotal}.

Use the explicit formatter only when you want to control the output, such as dateStyle:long or a custom money divisor.

ts
const publishedAt = new Date('2026-03-14T09:00:00Z');
const renewalTotal = {
  amount: 1900,
  currency: 'USD',
};
 
const updatedLabel = await engine.t('Last updated {publishedAt}', {
  vars: { publishedAt },
});
 
const totalLabel = await engine.t('Renewal total {renewalTotal}', {
  vars: { renewalTotal },
});
 
const detailedDate = await engine.t('Detailed date: {publishedAt, date, dateStyle:long}', {
  vars: { publishedAt },
});

By default, money amounts are treated as minor units. If you already have major units, use the explicit money formatter with divisor: 1.

Select blocks

Use select when the copy depends on a small set of discrete values.

ts
const banner = await engine.t(
  '{isSignedIn, select, true{Welcome back, {name}} false{Sign in to continue} other{Sign in to continue}}',
  {
    vars: {
      isSignedIn: true,
      name: 'Ada',
    },
  }
);

Component composition

@18ways/core returns strings. If you need rich text, keep the sentence whole and handle markup in your own renderer.

ts
const cta = await engine.t('Click here to see more');

If your app needs automatic JSX composition, move up to @18ways/react or @18ways/next.

Practical rule

If the sentence can be written as a complete phrase with a few variables, keep it in one message. That makes translation quality dramatically better than stitching fragments together in code.

Đang đổi ngôn ngữ