akiver

i18n

Add or update translated strings in the CS Demo Manager UI using LinguiJS. Use when adding user-visible text, labels, placeholders, error messages, or any string that should be localized. Handles Trans, useLingui, Plural, msg macros, context disambiguation, and the extract workflow.

akiver 2.017 256 Actualitzat fa 3 mesos
GitHub

Instal·la

npx skillscat add akiver/cs-demo-manager/i18n

Instal·la des del registre de SkillsCat.

SKILL.md

Scope

Only src/ui/ and src/electron-main/ need translations. Server, node, and CLI code is exempt.

Patterns

Always Use Macros

Prefer macros over runtime components. Macros are compiled at build time, reducing bundle size:

// ✅ Good - uses macro
import { Trans } from '@lingui/react/macro';

// ❌ Avoid - runtime only
import { Trans } from '@lingui/react';

It's enforced by a lint rule!

Keep Messages Simple

Avoid complex expressions in messages - they'll be replaced with placeholders:

// ❌ Bad - loses context
<Trans>Hello {user.name.toUpperCase()}</Trans>;
// Extracted as: "Hello {0}"

// ✅ Good - clear variable name
const userName = user.name.toUpperCase();
<Trans>Hello {userName}</Trans>;
// Extracted as: "Hello {userName}"

Use Trans for JSX Content

The Trans macro is the primary way to translate JSX:

import { Trans } from "@lingui/react/macro";

// Simple text
<Trans>Hello World</Trans>

// With variables
<Trans>Hello {userName}</Trans>

// With components (rich text)
<Trans>
  Read the <a href="/docs">documentation</a> for more info.
</Trans>

// Extracted as: "Read the <0>documentation</0> for more info."

When to use: For any translatable text in JSX elements.

Use useLingui for Non-JSX

For strings outside JSX (attributes, alerts, function calls):

import { useLingui } from '@lingui/react/macro';

function MyComponent() {
  const { t } = useLingui();

  const handleClick = () => {
    alert(t`Action completed!`);
  };

  return (
    <div>
      <img src="..." alt={t`Image description`} />
      <button onClick={handleClick}>{t`Click me`}</button>
    </div>
  );
}

When to use: Element attributes, alerts, function parameters, any non-JSX string.

Use msg for Lazy Translations

When you need to define messages in arrays/objects:

import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';

function StatusList() {
  const { _ } = useLingui();

  const statuses = {
    active: msg`Active`,
    inactive: msg`Inactive`,
    pending: msg`Pending`,
  };

  return Object.entries(statuses).map(([key, message]) => <div key={key}>{_(message)}</div>);
}

When to use: Module-level constants, arrays of messages, conditional message selection.

Pluralization

Use the Plural macro for quantity-dependent messages:

import { Plural } from '@lingui/react/macro';

<Plural value={messageCount} one="You have # message" other="You have # messages" />;

The # placeholder is replaced with the actual value.

Exact Matches

Use _N syntax for exact number matches (takes precedence over plural forms):

<Plural value={count} _0="No messages" one="One message" other="# messages" />

With Variables and Components

Combine with Trans for complex messages:

<Plural
  value={count}
  one={`You have # message, ${userName}`}
  other={
    <Trans>
      You have <strong>#</strong> messages, {userName}
    </Trans>
  }
/>

Formatting Dates and Numbers

Use the native Intl API directly with the current locale.

For date formatting, prefer the useFormatDate hook:

import { useFormatDate } from 'csdm/ui/hooks/use-format-date';

function MyComponent() {
  const formatDate = useFormatDate();
  const lastLogin = new Date();

  return <Trans>Last login: {formatDate(lastLogin)}</Trans>;
}

For number formatting, use Intl.NumberFormat with the current locale:

import { useLocale } from 'csdm/ui/settings/ui/use-locale';

function MyComponent({ score }: { score: number }) {
  const locale = useLocale();
  const formatted = new Intl.NumberFormat(locale).format(score);

  return <Trans>Score: {formatted}</Trans>;
}

Message IDs and Context

Explicit IDs

Only use explicit id in src/electron-main/ — never in the renderer process.

The electron-main process requires explicit IDs because it uses a separate JSON catalog and cannot rely on auto-generated IDs from JSX extraction:

// ✅ electron-main only
t({ id: 'notification.download.complete', message: 'Download complete' });

// ❌ Never in src/ui/ — let the macro generate the ID
<Trans id="some.id">Download complete</Trans>;

Context for Disambiguation

When the same text has different meanings, use context:

<Trans context="direction">right</Trans>
<Trans context="correctness">right</Trans>

These create separate catalog entries.

Comments for Translators

Add context for translators:

<Trans comment="Greeting shown on homepage">Hello World</Trans>

Electron Main Process

src/electron-main/ has its own Lingui config (src/electron-main/lingui.config.ts) and uses JSON catalogs instead of .po. The same macro rules apply; use i18n from @lingui/core directly (no React provider).

After adding or changing strings

Re-generate the catalogs (both UI and electron-main):

vp run i18n:extract

Only the English source catalogs (src/ui/translations/en/messages.po and src/electron-main/translations/en/messages.json) are committed — commit those. The other locales are gitignored, managed on Crowdin, and downloaded at build time, so leave them untracked and never translate them by hand.