CI/CD for Non-Native Projects
The Stringhive CLI ships as an npm package, but your project doesn't have to be a Node.js app to use it. Any codebase that stores translations as JSON files can integrate Stringhive in CI by installing Node only for the sync steps — your primary language and toolchain stay unchanged.
How it works
Your translation files live wherever they normally do. In CI, you install Node and the stringhive CLI, point it at those files with --lang-path, and run push, pull, or audit. The rest of your pipeline is unaffected.
Requirements
- Node.js 22 or higher in your CI environment (for the sync steps only)
- Source strings stored as a flat or nested JSON file
- A Stringhive API token
Setup
Install the CLI globally in CI — no package.json needed:
npm install -g stringhive
Configure with environment variables so no config file is required:
STRINGHIVE_TOKEN=shv_yourtokenhere
STRINGHIVE_HIVE=my-app
Then run commands with --lang-path pointing at your translations directory:
stringhive push --lang-path ./path/to/locales --conflict-strategy keep
stringhive pull --lang-path ./path/to/locales
stringhive audit --fail-on-missing
GitHub Actions examples
Ruby on Rails
A Rails app that keeps its frontend translations as JSON in public/locales/:
name: Stringhive Sync
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
push-strings:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node (Stringhive CLI only)
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Stringhive CLI
run: npm install -g stringhive
- name: Push source strings
run: stringhive push my-app --lang-path public/locales --conflict-strategy keep
env:
STRINGHIVE_TOKEN: ${{ secrets.STRINGHIVE_TOKEN }}
audit:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm install -g stringhive
- name: Audit translation keys
run: stringhive audit my-app --lang-path public/locales --fail-on-missing
env:
STRINGHIVE_TOKEN: ${{ secrets.STRINGHIVE_TOKEN }}
Python / Django
A Django project with frontend translations under locale/en/:
name: Stringhive Sync
on:
push:
branches: [main]
jobs:
push-strings:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node (Stringhive CLI only)
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Stringhive CLI
run: npm install -g stringhive
- name: Push source strings
run: stringhive push my-django-app --lang-path locale/en --conflict-strategy keep
env:
STRINGHIVE_TOKEN: ${{ secrets.STRINGHIVE_TOKEN }}
Pull before build
Add a pull step before your compilation or asset pipeline regardless of language:
- name: Set up Node (Stringhive CLI only)
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Stringhive CLI
run: npm install -g stringhive
- name: Pull translations
run: stringhive pull my-app --lang-path public/locales
env:
STRINGHIVE_TOKEN: ${{ secrets.STRINGHIVE_TOKEN }}
# Continue with your normal build — Rails, Django, Go, etc.
- name: Build
run: make build
Caching the CLI installation
If your pipeline has multiple Stringhive steps, cache the global npm install to avoid downloading the package twice:
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Cache Stringhive CLI
uses: actions/cache@v4
with:
path: ~/.npm-global
key: stringhive-cli-${{ runner.os }}
- name: Install Stringhive CLI
run: |
npm config set prefix ~/.npm-global
npm install -g stringhive
echo "$HOME/.npm-global/bin" >> $GITHUB_PATH
Using the programmatic client in custom scripts
When CLI flags aren't enough — for example, you need to transform keys before pushing or write translations to a non-standard location — use the StringhiveClient directly in a Node.js script you call from CI:
// scripts/sync-translations.ts
import { StringhiveClient } from 'stringhive'
import { readFileSync, writeFileSync } from 'fs'
const client = new StringhiveClient() // reads STRINGHIVE_TOKEN from env
const raw = JSON.parse(readFileSync('./locales/en.json', 'utf-8'))
// transform keys to match your app's format before pushing
const strings = Object.entries(raw).map(([key, value]) => ({ key, value: String(value) }))
await client.importStrings('my-app', { strings })
console.log('Pushed', strings.length, 'source strings')
Then call it from CI with npx tsx scripts/sync-translations.ts or compile it first.
Token scoping
| Step | Required ability |
|---|---|
push |
Write |
pull |
Read |
audit |
Read |
Scope push and pull to separate secrets so a leaked Read token can't overwrite your source strings.