Skip to content
Back to skills

Conventions I18n

ASecurity

Internationalization conventions for Stella. Apply when adding or modifying user-facing strings.

  • 257 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
developmentgogitdatabase

Works with

  • cli

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add stella/stella --skill conventions-i18n --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Conventions I18n?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Conventions I18n
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/stella-conventions-i18n/badge)](https://www.skillsdirectory.com/skills/stella-conventions-i18n)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: conventions-i18n
description: "Internationalization conventions for Stella. Apply when adding or modifying user-facing strings."
---

# i18n Conventions

Internationalization conventions for Stella. Apply when adding or
modifying user-facing strings.

## Stack

`use-intl` for runtime.

## Supported Languages

en is the source language. Check `apps/web/src/i18n/langs/` for
the current list of target languages (add translations to every
`.json` file found there).

## Translation Flow

1. Add or modify keys in
   `apps/web/src/i18n/langs/en.json`.
2. Add corresponding translations to **all target language files**
   found in `apps/web/src/i18n/langs/` (every `.json` file
   except `en.json`). Write natural, idiomatic translations;
   avoid literal/robotic phrasing.
3. Run `bun run i18n:sync` from `apps/web`. This synchronizes locale
   structure, regenerates typed messages, and updates generated glossary
   output. Never edit `messages.gen.ts` or generated terminology tables by
   hand.
4. Run `bun run i18n:check` from `apps/web`. Typecheck does not regenerate or
   validate the catalogs, so a clean typecheck is not evidence that i18n is in
   sync.
5. Read the rendered sentence in context, including interpolation and plural
   branches. Passing key parity is not proof that a translation is natural or
   that placeholders remain grammatically valid.

## Key Naming

**Prefer generic, reusable keys over feature-specific ones.**
Before adding any new i18n key, search `en.json` for an existing
key with the same or similar wording (e.g., `common.filter`,
`common.sort`, `common.columns`). Reuse `common.*` or shared
namespace keys instead of creating feature-scoped duplicates
like `billing.expenses.deleteExpense`. Feature-specific keys
are only justified when the wording truly differs from the
generic version (e.g., a confirmation message that mentions
the resource by name).

When a translation key crosses indirection through a constant, map, prop, or
helper return type, type it with `TranslationKey` from
`apps/web/src/i18n/types.ts` instead of `string`. Missing or stale keys must
fail typecheck at the point where they are stored.

Prefer complete translatable sentences over fragments assembled in JSX. Keep
interpolation variables semantic (`{documentName}`, not `{value}`), use ICU
plural/select branches for grammatical variation, and never concatenate
translated fragments whose word order differs by locale.

**Never call anything an "entity" in user-facing copy**, in English or as a
calque (`entita`, `Entität`, `entidad`, `entité`, `entidade`, `encja`, ...).
It is the database's word for a row and means nothing to a lawyer. Name the
concrete thing the string is about — document, file, folder, task, matter —
and fall back to "item" only when the string genuinely covers all of them. In
anonymization, what the detector finds is a **match**, not an entity. The
`item` concept in `glossary.json` enforces this with `forbiddenAlways`, so it
fires on the English source too, not only on translations.

Key naming, pluralization, and style rules are documented
in `apps/web/src/i18n/TERMINOLOGY.md`.

## Terminology (glossary)

Canonical legal/domain terms live in
`apps/web/src/i18n/glossary.json` (the source of truth);
`glossary-gen` renders them into the tables in `TERMINOLOGY.md`.
The `i18n-lint` checker enforces them: per concept it flags a
translation that uses a `forbidden` rendering when the English
source is about that concept (concept-gated, so a common word only
fires in the right context).

When introducing a NEW concept (or changing a preferred term):

1. **Research it first.** Confirm the sector-standard term and the
   synonyms to avoid in **each** language against authoritative
   sources (IATE/EU terminology, national legal glossaries,
   established legal-tech usage) — do not guess. Record the
   rationale in the concept's `note`.
2. **Add it to `glossary.json`**, never only to `TERMINOLOGY.md`
   (the `.md` is generated). Run `bun run i18n:sync` (from
   `apps/web`) to regenerate the tables.
3. **Account for declensions/inflections.** The lint matches
   forbidden terms whole-word (English source triggers also match
   their regular plural), so list the actual inflected, declined,
   and compound forms a translator might use — e.g. de
   `Sache`/`Sachen`/`Mandatsdaten`, sk `Vec`/`veci`/`vecou`, et
   `asi`/`asja`/`asjad`. A base form alone misses inflected drift.
4. **Pick the right ban field.** `forbidden` is concept-gated: it fires
   only where the English source names the concept (or a `keyTriggers`
   path matches), which is what stops a common word from false-firing
   everywhere. `forbiddenAlways` drops that gate, for wording that is
   wrong in every context. Use it when a concept-gated ban would go
   blind the moment someone rewords the English source, and only once
   you have checked that no legitimate use of the word exists in that
   locale.
5. **Apply consistently.** `bun run i18n:check` fails on new
   forbidden renderings; fix the translations, or — only for
   genuine pre-existing debt — grandfather with
   `i18n-lint <dir> --write-baseline` and flag for native review.

## Landing (marketing) catalogs

The landing app has its own catalogs (`apps/landing/src/i18n/messages/`)
with the same glossary enforcement plus marketing-specific rules —
register per locale, the identity phrase, hero structure differences,
meta-string length budgets, cognate policy, and brand handling. Before
translating landing strings, read
`apps/landing/src/i18n/TRANSLATION.md`; it explains the intent behind
each rule so translations stay coherent rather than merely passing the
checks. Landing gates: `bun run i18n:sync` and `bun run i18n:check`
from `apps/landing`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.