LingoSeal CLI
Command-line tool for pushing and pulling translations between your project and LingoSeal.
Installation
The CLI is distributed as a tarball (.tgz file). Download the latest build below.
Download lingoseal-cli-latest.tgz
# Install globally
npm install -g ./lingoseal-cli-latest.tgz
# Or install as a dev dependency in your project
npm install --save-dev ./lingoseal-cli-latest.tgzAfter installing, the lingoseal command is available globally, or via npx lingoseal if installed locally.
Quick Start
# 1. Initialize a config file in your project root
lingoseal init --url https://app.lingoseal.com --project <project-id> --token <api-token>
# 2. Review and edit lingoseal.config.js if needed
# 3. Download translations (pull)
lingoseal download
# 4. Push local translation files to the server
lingoseal push --include-baseGetting Your API Token
- Open your project in LingoSeal
- Go to the Settings tab
- Under Public API Token, click Generate Token
- Copy the token into
lingoseal.config.jsor pass it via--token
Commands
All commands read from lingoseal.config.js by default. CLI flags override config values.
lingoseal init
Creates a lingoseal.config.js configuration file in the current directory.
lingoseal init
lingoseal init --url https://app.lingoseal.com --project abc-123 --token my-secret-token| Option | Description |
|---|---|
--url <url> | Base URL of the LingoSeal server |
--project <id> | Project ID (find it in your project URL) |
--token <token> | API token from project settings |
lingoseal download
Downloads translations from the server and writes them as JSON files.
# Using config file (default: lingoseal.config.js)
lingoseal download
# Override config values via CLI
lingoseal download \
--url https://app.lingoseal.com \
--project abc-123 \
--token my-secret-token \
--output ./src/locales \
--format nested-json
# Download specific languages only
lingoseal download --languages en,de,fr
# Use short language codes (en instead of en-US)
lingoseal download --short-codes --include-base| Option | Description | Default |
|---|---|---|
-c, --config <path> | Path to config file | lingoseal.config.js |
-u, --url <url> | Base URL of translation server | - |
-p, --project <id> | Project ID | - |
-t, --token <token> | API token | - |
-o, --output <path> | Output directory | ./locales |
-f, --format <format> | Output format | flat-json |
-l, --languages <langs> | Comma-separated languages | all |
--include-base | Include base language | false |
--short-codes | Use short language codes (en instead of en-US) | false |
lingoseal push
Pushes local translation files to the server. Reads files from your output directory, parses them based on the configured format, and uploads them via the public API.
# Push all translation files (excluding base language by default)
lingoseal push
# Preview what would change without applying
lingoseal push --dry-run
# Push including the base (source) language
lingoseal push --include-base
# Push specific languages only
lingoseal push --languages de,fr
# Overwrite existing translations on the server
lingoseal push --conflict-strategy overwrite
# Only fill in empty translations
lingoseal push --conflict-strategy overwrite-empty| Option | Description | Default |
|---|---|---|
-c, --config <path> | Path to config file | lingoseal.config.js |
-u, --url <url> | Base URL of translation server | - |
-p, --project <id> | Project ID | - |
-t, --token <token> | API token | - |
-i, --input <path> | Input directory (overrides outputPath) | ./locales |
-f, --format <format> | File format: flat-json, nested-json, i18next | flat-json |
-l, --languages <langs> | Comma-separated languages to push | all found |
--conflict-strategy <s> | How to handle existing keys (see below) | sync |
--dry-run | Preview changes without writing to the server | false |
--include-base | Include the base language | false |
--short-codes | Map short codes in filenames to full codes | false |
Conflict Strategies
| Strategy | Behavior |
|---|---|
sync | Default. Add new keys, update existing, and delete keys missing from any language file. |
overwrite | Create new keys and update all existing translations. No deletions. |
skip | Only create new keys. Don’t touch existing translations. |
overwrite-empty | Create new keys. Only update translations that are currently empty on the server. |
Dry Run Output
When using --dry-run, the CLI shows what would change without applying anything:
📤 LingoSeal Translation Push
✓ Project: My App
Base language: en
Supported languages: en, de, fr, cs-CZ
Conflict strategy: overwrite
Mode: DRY RUN (no changes will be made)
Pushing 2 language(s)...
Pushing de... ✓ 150 keys (+3 new, ~12 updated, 135 unchanged)
+ settings.notifications: "Benachrichtigungen"
+ settings.theme: "Design"
~ home.title: "Startseite" → "Willkommen"
~ nav.login: "Anmelden" → "Einloggen"
... and 10 more changed keys
Pushing fr... ✓ 150 keys (+3 new, ~8 updated, 139 unchanged)
✓ Dry run complete (no changes applied)
Summary:
New keys created: 6
Keys updated: 20
Keys skipped: 0
Keys unchanged: 274Configuration File
Create a lingoseal.config.js in your project root (or use lingoseal init):
/** @type {import('lingoseal-cli').LingoSealConfig} */
module.exports = {
// Required
url: "https://app.lingoseal.com",
projectId: "your-project-id",
token: "your-api-token",
// Optional
outputPath: "./src/locales", // Where to read/write translation files
format: "flat-json", // flat-json | nested-json | i18next
filePattern: "{lang}.json", // File naming pattern
languages: [], // Empty = all project languages
includeBase: true, // Include the base (source) language
namespace: "translation", // Namespace for i18next format
shortCodes: false, // Use en instead of en-US
};lingoseal.config.js to .gitignore if the token is sensitive, or leave the token out of the file and pass it via --token or a CI secret.File Patterns
| Placeholder | Description | Example |
|---|---|---|
{lang} | Language code | en, cs-CZ |
{ns} | Namespace | translation |
| Pattern | Output |
|---|---|
{lang}.json | en.json, cs-CZ.json |
{lang}/{ns}.json | en/translation.json |
locales/{lang}/translation.json | locales/en/translation.json |
The same file pattern is used by both download (to write files) and push (to discover files to upload).
Output Formats
flat-json (default)
Flat key-value pairs:
{
"home.title": "Welcome",
"home.description": "This is the homepage",
"nav.login": "Login"
}nested-json
Nested objects from dot-separated keys:
{
"home": {
"title": "Welcome",
"description": "This is the homepage"
},
"nav": {
"login": "Login"
}
}i18next
Wrapped in a namespace for i18next:
{
"translation": {
"home.title": "Welcome",
"home.description": "This is the homepage"
}
}CI/CD Integration
The recommended CI/CD setup uses two workflows: push source strings when they change, and pull the latest translations on a schedule.
Push on Merge
When source strings change on main, push them to LingoSeal so translators can start working immediately.
# .github/workflows/translations-push.yml
name: Push source translations
on:
push:
branches: [main]
paths:
- 'src/locales/en.json' # adjust to your base language file
jobs:
push-source:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install LingoSeal CLI
run: npm install -g ./lingoseal-cli-latest.tgz
- name: Push base language to LingoSeal
run: >
lingoseal push
--include-base
--languages en
--conflict-strategy overwrite
--token ${{ secrets.LINGOSEAL_TOKEN }}Pull on Schedule
Periodically pull the latest translations and open a PR for review.
# .github/workflows/translations-pull.yml
name: Pull translations
on:
schedule:
- cron: '0 6 * * 1-5' # Weekdays at 6am UTC
workflow_dispatch: # Allow manual trigger
jobs:
pull-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install LingoSeal CLI
run: npm install -g ./lingoseal-cli-latest.tgz
- name: Download translations
run: lingoseal download --token ${{ secrets.LINGOSEAL_TOKEN }}
- name: Create PR with updates
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: 'chore: update translations from LingoSeal'
title: 'chore: update translations from LingoSeal'
body: Automated translation update from LingoSeal.
branch: translations/update
delete-branch: truePreview in PRs
Add a CI check that previews what a push would do, without applying changes:
# .github/workflows/translations-preview.yml
name: Preview translation changes
on:
pull_request:
paths:
- 'src/locales/**'
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install LingoSeal CLI
run: npm install -g ./lingoseal-cli-latest.tgz
- name: Preview changes
run: >
lingoseal push --dry-run
--include-base
--conflict-strategy overwrite
--token ${{ secrets.LINGOSEAL_TOKEN }}Package Scripts
// package.json
{
"scripts": {
"translations:pull": "lingoseal download",
"translations:push": "lingoseal push --include-base --conflict-strategy overwrite",
"translations:preview": "lingoseal push --dry-run --include-base --conflict-strategy overwrite",
"prebuild": "npm run translations:pull"
}
}Framework Examples
Example configurations for popular i18n libraries.
react-i18next
// lingoseal.config.js
module.exports = {
url: "https://app.lingoseal.com",
projectId: "your-project-id",
token: "your-api-token",
outputPath: "./src/locales",
format: "flat-json",
filePattern: "{lang}/translation.json",
includeBase: true,
shortCodes: true,
};// i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import en from './locales/en/translation.json';
import de from './locales/de/translation.json';
i18n.use(initReactI18next).init({
resources: {
en: { translation: en },
de: { translation: de },
},
lng: 'en',
fallbackLng: 'en',
});next-intl
// lingoseal.config.js
module.exports = {
url: "https://app.lingoseal.com",
projectId: "your-project-id",
token: "your-api-token",
outputPath: "./messages",
format: "nested-json",
filePattern: "{lang}.json",
includeBase: true,
};Building & Distributing
For maintainers who need to build and distribute the CLI:
cd cli
# Install dependencies & build & create tarball
npm install
npm run pack:dist
# Output: lingoseal-cli-latest.tgzShare the .tgz file with team members via Slack, shared drive, or your internal file sharing tool. Recipients install with:
npm install -g lingoseal-cli-latest.tgzRequirements
- Node.js >= 18.0.0