Best practices

The fastest way to get bad translations is to make the runtime work around avoidable app structure problems.

Use real context names

Good context keys explain where the copy lives:

ts
await engine.t('Pay now', {
  context: 'checkout.payment-form',
});
 
await engine.t('Billing history', {
  context: 'dashboard.billing-history',
});
 
await engine.t('Simple pricing', {
  context: 'marketing.pricing-hero',
});

Avoid anonymous buckets like page1, copy, or misc.

Translate complete thoughts

Good:

ts
const label = await engine.t(
  'Download your latest invoice as PDF'
);

Avoid:

18ways can handle the common link case as one message. <T><a href="#">Click here</a> to see more</T> should stay as one sentence instead of being split apart and stitched back together.

ts
const first = await engine.t('Download');
const second = await engine.t(
  'your latest invoice'
);
const third = await engine.t('as PDF');
 
const stitched = [first, second, third].join(' ');

Keep the package boundary clear

  • If you are in Next.js, use @18ways/next for locale resolution and metadata.
  • If you are only in React, keep locale state in your app and use @18ways/react.
  • If you are outside React, use @18ways/core and own the UI integration yourself.

Let routing match your product

Public marketing pages usually want path-based locale routing for SEO. Internal dashboards often do not. That is why the current site excludes /dashboard from path routing.

Keep source copy human

18ways works best when the source text reads like real product copy, not like a compressed translation key.

Good source copy gives the model better context and gives your team something readable in code.