shiptxt
v0.1.0
Published
CLI to pull i18n translations from a shiptxt server
Downloads
14
Maintainers
Readme
shiptxt
CLI to pull Figma translations from a shiptxt server into your project.
Install
npm install -g shiptxt
# or use without installing
npx shiptxt initQuick start
# 1. Run the setup wizard once
npx shiptxt init
# 2. Open the Figma plugin and sync a frame
# 3. Pull translations
npx shiptxt pullThat's it. Translation files are written to ./public/locales (or wherever you configured).
Commands
shiptxt init
Interactive wizard that creates .shiptxt.json in your project root.
$ shiptxt init
shiptxt init
This creates .shiptxt.json in your project root.
Server URL (e.g. https://api.shiptxt.app): https://api.shiptxt.app
API Key (from dashboard → Settings, or ${ENV_VAR_NAME}): ${SHIPTXT_KEY}
Output directory [./public/locales]:
Format (namespaced / flat) [namespaced]:
Testing connection... ✅ Connected
✅ Created .shiptxt.json
Next steps:
1. Open the Figma plugin and sync a frame
2. Run: shiptxt pull
3. Commit .shiptxt.json (config) and .shiptxt.lock (lock file)shiptxt pull
Downloads the latest translations from the server and merges them safely into your locale files.
$ shiptxt pull
shiptxt pull
server : https://api.shiptxt.app
out : ./public/locales
format : namespaced
📥 Fetching job a1b2c3d4… "Marketing / Hero"
✅ +12 new · ~3 updated
Written to : ./public/locales (4 languages)
Lock file : .shiptxt.lockSafe merge
pull never deletes keys you have locally — it only adds and updates. If a key existed in the previous sync but was removed from the design, it is flagged as stale and kept:
⚠ 2 stale
Stale keys (removed from design, kept locally):
- pt:hero.cta_secondary
- es:hero.cta_secondaryReview stale keys manually and remove them if they're no longer needed.
shiptxt status
Checks whether new translations are available without downloading anything. Useful in CI to gate deploys.
$ shiptxt status
shiptxt status
Latest job : a1b2c3d4… "Marketing / Hero"
Created : 2h ago
📦 New translations available!
Local : 9f8e7d6c… "Marketing / Hero"
Remote : a1b2c3d4… "Marketing / Hero"
Run: shiptxt pullExit codes:
0— up to date1— error (server unreachable, bad key, etc.)2— new translations available
Config file
.shiptxt.json in your project root:
{
"server": "https://api.shiptxt.app",
"key": "${SHIPTXT_KEY}",
"out": "./public/locales",
"format": "namespaced"
}| Field | Required | Default | Description |
|---|---|---|---|
| server | ✅ | — | URL of your shiptxt server |
| key | ✅ | — | API key from the dashboard → Settings |
| out | | ./public/locales | Directory to write translation files |
| format | | namespaced | namespaced or flat (see below) |
CLI flags --server, --key, --out, --format override the config file.
API key security
Never commit your API key in plain text. Use an env var instead:
{ "key": "${SHIPTXT_KEY}" }Then set the variable in your environment or CI secrets:
# local
export SHIPTXT_KEY=sk-...
# GitHub Actions
# Settings → Secrets → SHIPTXT_KEYIf you store the key as plain text, the init command will warn you and suggest adding .shiptxt.json to .gitignore.
Output formats
namespaced (default)
One file per language per frame, compatible with react-i18next and similar libraries:
public/locales/
en/
marketing_hero.json
pt/
marketing_hero.json
es/
marketing_hero.json{
"hero.headline": "Ship faster",
"hero.cta": "Get started"
}Load in react-i18next:
const { t } = useTranslation("marketing_hero");
t("hero.headline"); // "Ship faster"flat
All keys for a language in a single file:
public/locales/
en.json
pt.json
es.jsonLock file
.shiptxt.lock tracks the last synced job. Commit it to your repo.
{
"jobId": "a1b2c3d4-...",
"syncedAt": "2026-02-26T10:00:00.000Z",
"frameName": "Marketing / Hero",
"keys": {
"hero.headline": "Ship faster",
"hero.cta": "Get started"
}
}The lock file enables:
- Idempotent pulls — running
pulltwice doesn't duplicate keys - Stale detection — keys removed from the design are flagged, not silently deleted
- CI gates —
statuscompares lock vs server to decide if a re-pull is needed
CI / CD example
# .github/workflows/i18n.yml
name: Check translations
on: [push]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Check for new translations
run: npx shiptxt status
env:
SHIPTXT_KEY: ${{ secrets.SHIPTXT_KEY }}
# exits with code 2 if translations are stale — fails the jobOr auto-pull and open a PR:
- name: Pull latest translations
run: npx shiptxt pull
env:
SHIPTXT_KEY: ${{ secrets.SHIPTXT_KEY }}
- name: Open PR if changed
uses: peter-evans/create-pull-request@v6
with:
title: "chore: update translations"
branch: translations/auto-update