agentsclimarketplace

Write translations

Skill tale-project/tale/.agents/skills/write-translations

The Orchestrator for AI Agents — Connect OpenClaw, Hermes Agent, Claude Code, Codex, Cursor, Gemini CLI, OpenCode, Pi, and Qwen Code. Pool their knowledge, delegate tasks, and build your swarm of agents.

Install
npx -y skills add tale-project/tale --skill write-translations

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill whenever you edit any non-English file under services/*/messages/ (e.g. de.json, fr.json), packages/ui/src/i18n/messages/, or any page under docs/<locale>/, add a locale, or touch a glossary term — Tale ships as one narrator written natively per language, never a word-for-word render of the English. Load it before touching any non-English string; never translate by rendering the source words. Per-locale voice doctrine lives in locales/<locale>/AGENTS.md; the loanword buckets in BUCKETS.md, the conventions template in CONVENTIONS.md, the glossary workflow in GLOSSARY_GUIDE.md.

SKILL.md

9.8 KB, as published. Nobody here has run it

write-translations

Tale ships one calm, opinionated, second-person-informal narrator in three languages — the German page is the same voice written natively in German, never a German rendering of the English. This file is the cross-locale contract; the data that changes between languages (strike lists, drift patterns, gender maps, formal-pronoun denylists) lives in the framework's per-locale test data under packages/ui/src/i18n/tests/locales/ and the per-locale voice files. Read this first, then the locale file for the locale you're in.

When this applies

Editing any non-English value under services/*/messages/ (e.g. de.json, fr.json), packages/ui/src/i18n/messages/, or any page under docs/<locale>/. Then read locales/<locale>/AGENTS.md for that language's voice doctrine and drift catalogue. The two reliable failure modes are bureaucratic German (passive present, sentence-final erfolgreich, third-person Sie) and marketed French (Découvrez, N'hésitez pas à, stacked nominal phrases) — both translate the words and lose the voice.

Write a note first

Invoke write-notes and record your answers to this form before you translate:

  • Locale & files: Describe the locale and files, and the source meaning you must convey (not the words).
  • Voice risk: Describe this locale's drift mode to avoid (bureaucratic German / marketed French) and how you'll keep the native voice.
  • Must-match: Describe the UI labels and compound terms that must stay exact, and how you confirmed them against the shipped strings.
  • Risks & unknowns: Describe where the translation might read non-natively or drift from the source meaning.

The rules

These four fail review. The first is reviewer-caught (voice doesn't lint cleanly); the rest are enforced by the i18n test suite (see Patterns).

  • Same voice across locales. Translation is a rewrite of the same narrator in another language, not a render of the source words — translate meaning, not words. Sentence structure, idiom, and noun choice all differ: the German equivalent of an English three-clause sentence is often one sentence with a verb-final subordinate clause; the French equivalent of a stacked English noun phrase is often a relative clause. A page that reads calmly in English and bureaucratically in German has a tone bug; fix the wording. The drift modes are language-specific — your per-locale file names yours. (reviewer-caught)

  • Informal pronoun, always. du in DE and de-CH, tu in FR. Never Sie, never vous — formal pronouns put distance between Tale and the reader. The carve-out for sentence-initial DE Sie (third-person feminine) is built into the check. (enforced by pronouns-formal)

  • The shipped UI string is the source of truth. Every button, menu, panel, or feature name in a translated page matches services/platform/messages/<locale>.json exactly. When JSON and a glossary or doc disagree, the JSON wins — the contract bends to what ships. Half-translated walkthroughs (Öffne **Settings > Members**) are the most common bug. (enforced by terminology-ui-label)

  • Compound terms are whole or kept whole. Pull Request stays English in DE/FR; Knowledge Base translates whole to Wissensdatenbank / Base de connaissances. Half is always wrong — Pull Anfrage, Code Review-Prozess, Merge-Anfrage fail. Whether a compound stays English or translates is a bucket decision (see BUCKETS.md); whether it's a half is the rule. (enforced by terminology-half-compound)

Patterns

A correct translation that correctly does not translate one thing:

EN: Open a pull request from your feature branch. The CI pipeline runs against the head of the branch; the merge into main is gated on green.

DE: Öffne einen Pull Request aus deinem Feature-Branch. Die CI-Pipeline läuft gegen den Kopf des Branches; der Merge in main ist erst möglich, wenn die Pipeline grün ist.

Pull Request, Feature-Branch, CI, Pipeline, Merge, Branch stay English (Git-domain loanwords; bucket 2). du, never Sie. No erfolgreich, no Wird X…. The English-kept terms are the words a German-speaking developer uses without thinking — not lazy translation.

The shipped UI read back to the reader:

Drift: Open Settings > Members und klicke auf Invite member.

Target: Öffne Einstellungen > Mitglieder und klicke auf Mitglied einladen.

The reader sees the German UI; the page must echo it. Specifics: code identifiers stay English everywhere (CLI flags tale deploy --detach, env vars TALE_CONFIG_DIR, file paths, API paths POST /api/v1/documents); role names ship per locale (Owner / Inhaber / Propriétaire); parenthetical lists translate ((Products, Customers, Vendors)(Produkte, Kunden, Lieferanten)); navigation paths translate segment by segment (Settings > MembersEinstellungen > Mitglieder, never Einstellungen > Members).

Three buckets, summary (full lists + assignment in BUCKETS.md):

BucketExamplesBehaviour
Always EnglishTale, Convex, AI, LLM, MCP, env vars, CLI flagsNever translates — brand, acronym, code identifier.
Established loanwordsWorkflow, Dashboard, Webhook, Pull Request, Branch, MergeStays English in DE/FR; hyphenated in DE compounds.
Translate-bucketHeader → Kopfzeile, Request → Anfrage, Email → E-MailMust translate in DE/FR/de-CH; caught by terminology-loanword.

The bucket lives on each term's entry in tests/glossary/glossary.json. Moving a term between buckets is a glossary PR, not a skill PR.

What the suite catches — two layers run on every bun run check: parity + usage (sibling test files in each consumer's lib/i18n/ — key parity, orphan detection), and the centralized @tale/ui/i18n/tests — 26 checks (the registry's 28 entries in tests/registry.ts minus parity + usage) over terminology, voice, grammar, style, ICU parity, heuristics, and markdown. Most start in report mode during rollout; flip to enforce after findings clear. Not caught — reviewer territory: subtler calques past the small denylist, tone drift inside passing prose, sentence flow across clauses, ICU plural correctness within branches, idiomatic word choice (Duden-correct ≠ native-sounding).

Adding a locale (e.g. Italian) — three concerns:

  1. Runtime registry — add it to SUPPORTED_LOCALES in packages/ui/src/i18n/locales.ts.
  2. Test framework data — create packages/ui/src/i18n/tests/locales/it/ with index.ts, style.ts, voice.ts, terminology.ts, grammar.ts, patterns.ts, and a planted/ folder of positive/negative fixtures per applicable check; register it. The startup-drift assertion in locales/index.ts keeps the runtime and test registries in sync. Optionally extend glossary.json with it forms on translating terms.
  3. Doctrine — create locales/it/AGENTS.md per the template in the existing locale files, and add its row to Companion files below.

Before you call the translation done

Tick every box, or N/A with a reason:

  • Same voice as the source — rewritten natively, not word-rendered; no bureaucratic German, no marketed French.
  • Informal pronoun throughoutdu (DE/de-CH), tu (FR); never Sie/vous.
  • Every UI label matches services/platform/messages/<locale>.json exactly — no half-translated walkthroughs.
  • Compound terms whole or kept whole — no Pull Anfrage / Merge-Anfrage; bucket decisions honoured.
  • en.json parity — every key present, dead keys removed everywhere; de-CH holds only overrides.
  • The i18n suite is greenbun run check.

Companion files

  • locales/<locale>/AGENTS.md — read when editing that locale's JSON or docs: the voice doctrine and language-specific drift catalogue (en, de, fr, and the de-CH Swiss overlay of differences-from-DE only).
  • BUCKETS.md — read when deciding whether an English term translates, stays English, or matches the UI verbatim; holds the full per-bucket lists, the assignment workflow, and the half-compound denylists.
  • CONVENTIONS.md — read when handling quotes, apostrophes, dates, numbers, currency, percent, NBSP, dashes, or ß: the 14-row conventions template every locale fills.
  • GLOSSARY_GUIDE.md — read when adding a glossary term, choosing its category, or using _lintExclude to defer a UI-vs-bucket mismatch; also documents the role table and the audit script.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.