mcpField
S
svintl

svintl

github.com/temichDevelopment6269 installsUpdated 2w ago
Repository

About svintl

svintl is a CLI for managing Svelte internationalization dictionaries, aimed at developers maintaining localized apps. It generates translation files and supports OpenAI-assisted locale creation, dynamic values, pluralization, and separate mounts.

Key features

  1. 01Manage dictionaries with CLI commands
  2. 02Generate translations with OpenAI
  3. 03Handle placeholders and plural rules
  4. 04Organize translations into mounts

Use cases

  1. 01Add or update translation keys in bulk
  2. 02Generate locale dictionaries from context
  3. 03Use dynamic phrases and plural forms
  4. 04Separate translations by application area

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/temich/svintl --skill svintl

After installing, type/svintlin Claude Code to confirm it loaded.

Details

From the project README

svintl — i18n for Svelte

CLI tool for managing internationalization dictionaries with automatic translation via OpenAI.

Core Rule

The *.yaml, built.js, and types.ts files in intl directories are generated — they're edited through the npx intl CLI, not by hand.

CLI Commands

npx intl hola                               # init dictionaries (default: src/lib/intl/)
npx intl hola -p ./custom/path              # init at custom path
npx intl add key.path "Value" "context"     # add a new key — fails if it already exists; context optional
npx intl set key.path "Updated value"       # update a key that already exists — fails if missing
npx intl set "mount/key.path" "Value"       # target a mount with the mount/ prefix
npx intl add --from strings.yaml            # many new keys in one run — `key: value` or `key: { value, context }`, flat (`a.b: …`) or nested (`a: { b: … }`)
npx intl set --from strings.yaml            # many existing keys in one run; `--from -` reads stdin
npx intl add key.path "Value" --debug       # --debug (add or set): print the OpenAI request first
npx intl create de --tokens 60000           # --tokens (any command): output-token limit per OpenAI request, default 30000
npx intl const key.path "Same everywhere"   # same value across all locales (no translation)
npx intl unit items.count "item"            # pluralized entry (auto-generates plural forms)
npx intl move old.key new.key               # rename key/branch
npx intl del key.path                       # delete key/branch
npx intl create es                          # add a locale (BCP 47 tag) — auto-translates the whole dictionary into it
npx intl destroy es -y                      # delete locale (without -y it fails)
npx intl mount foo ./any/path               # create empty mount
npx intl import foo ./any/path              # adopt existing dict dir as mount, reconcile locales
npx intl unmount foo                        # remove mount (keeps files)
npx intl context "Project description"      # set project-wide translation guidance
npx intl context --clear                    # clear project context
npx intl genders he she none                # enable gender-aware translations (list the gender values)
npx intl genders                            # print current gender values
npx intl sync en key.path                   # reconcile: re-translate one key into all locales from source en
npx intl sync en                            # reconcile: re-translate the whole dictionary from source en
npx intl build                              # rebuild JS/TS from YAML

Dictionary Format

YAML with arbitrary nesting, strings at leaves:

native: English
example:
  hello: "Hello world"

Usage: {$dict.example.hello}

Dynamic Values — Placeholders

For simple cases the CLI auto-generates !js functions from placeholder syntax — no need to write them manually:

npx intl set greeting "Hello, {name}!"            # {name} → function param
npx intl set joined "[names] joined {groupName}"  # [names] → Intl.ListFormat

For complex logic, pass !js functions via intl set:

npx intl set greeting '!js (count) => `${count || "No"} item${count === 1 ? "" : "s"}`'

Usage in components: {$dict.greeting(user.name)}

Keep the whole phrase in the dictionary. Never split a sentence around a dynamic value in the template:

<!-- ❌ Wrong: breaks the phrase for translators -->
<strong>{brand}</strong>{$dict.form.destroyDescription}

<!-- ✅ Right: one entry, function accepts the value -->
{@html $dict.form.destroyDescription(brand)}
npx intl set "apps/form.destroyDescription" \
  '!js (brand) => `<strong>${brand}</strong> and all accumulated data will be permanently deleted.`'

When a name needs markup and is always at the start of the phrase across languages, put the tags inside the !js function and render with {@html} — escape user-controlled values before passing them in.

Pluralization

Use npx intl unit — generates Intl.PluralRules-based functions:

npx intl unit items.count "item"

Produces:

items:
  count:
    - one: item
      other: items

Usage: {$dict.items.count(count)}

Complex locales (Russian, Arabic) auto-get few, many, etc.

Genders

When enabled (npx intl genders he she none), gender-dependent phrases become functions whose last argument is the gender ('he' | 'she' | 'none') — the phrase's own arguments come first, e.g. (name, gender) => …. The listed values become the generated Grammar union.

Mounts

Organize translations into separate directories:

npx intl mount admin ./src/features/admin/intl
npx intl set "admin/dashboard.title" "Admin Dashboard"

Mount keys use {mount}/ prefix in CLI commands.

mount scaffolds an empty mount; import adopts a populated dir (with its own context.yaml) and reconciles its locales to the root — drops languages the root lacks, generates ones it lacks (translating the imported inputs), leaves shared locales untouched.

Import Pattern

Root dictionary:

<script lang="ts">
  import { dict, locale } from '$lib/intl'
</script>
<h1>{$dict.example.hello}</h1>

Mount dictionary:

<script lang="ts">
  import { dict } from './intl'
</script>
<h1>{$dict.dashboard.title}</h1>

Mount's intl/index.ts (#lib/intl/index.js instead of $lib/intl when package.json maps #lib/*, as in SvelteKit 3; mount and import write the form here, build writes it into built.js):

import { derived } from 'svelte/store'
import { locale } from '$lib/intl'
import { dictionaries } from './built.js'
import type { Locale, Dictionary } from './types'

const dict = derived(locale, ($locale) => dictionaries[$locale])
export { dict, dictionaries, locale }
export type { Locale, Dictionary }

Context for Translation Accuracy

npx intl set app.welcome "Welcome" "greeting shown on homepage"
npx intl context "B2B SaaS for enterprise users"

Context is stored in context.yaml and used by OpenAI when creating new locales.

Workflow

  1. Use npx intl add/set/unit/const to add/update translations — several keys go in one add --from / set --from file, never in a loop of npx intl calls
  2. Run npx intl build to generate JS/TS (often auto-runs)
  3. Import dict store in components
  4. Use $dict.key.path in templates

Avoid

  • Editing YAML by hand — go through the CLI
  • A loop over npx intl — each call is a process, a translation request and a build; write the keys to a file and run add --from once
  • const + sync to bulk-add — sync re-translates the whole dictionary; use add --from
  • npx intl sync for routine edits — it's only for reconciling after a manual source edit; use add/set instead
  • Non-BCP47 locale codes — use valid tags like en-US, es, pt-BR
  • Splitting phrases in the template — don't concatenate a dynamic value with a dictionary suffix/prefix; use one {placeholder} / !js entry for the full sentence

Comments

Markdown supported