Skip to content

GitHub Actions

Copy these pipeline files and customize as needed.

This workflow automatically extracts untranslated strings and translates them using Claude AI, then applies the translations back to your repository.

Workflow:

  1. Triggered when English locale files change on main branch
  2. Extracts new/changed strings using LocaleOps
  3. Sends strings to Claude API for translation
  4. Applies translated strings and creates a PR

Requirements:

  • GITHUB_TOKEN: Automatically provided by GitHub Actions
  • ANTHROPIC_API_KEY: Must be set in repository secrets

Setup Instructions:

1. Allow GitHub Actions to create and approve pull requests
- Go to Settings → Actions → General in your repository.
- Under "Workflow permissions", enable "Allow GitHub Actions to approve pull requests"
2. Enable AI Translations
Add your Anthropic API key as a GitHub secret:
- Go to Settings → Secrets and variables → Actions
- Add `ANTHROPIC_API_KEY`
localeops.ai.yml
name: AI translation
on:
push:
branches: [main]
paths:
- "src/i18n/locales/en/**" # Only trigger when English (source) locale changes
# Prevent multiple translation workflows from running simultaneously
concurrency:
group: localeops_ai
cancel-in-progress: false
jobs:
translate:
runs-on: ubuntu-latest
permissions:
contents: write # Required to push commits
pull-requests: write # Required to create pull requests
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Configure git for commits created by LocaleOps
- run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: extract and translate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub token for LocaleOps
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # Claude API key
run: |
set -e
# Step 1: Extract untranslated strings using LocaleOps
out=$(npx @localeops/localeops extract)
# Step 2: Transform extracted data into flat array for translation
# Collect all items needing translation (added or changed strings)
# Output format: [{locale, filePath, resourcePath, text}, ...]
to_translate=$(echo "$out" | jq '[to_entries[] | .key as $loc | .value[] | select(.type == "added" or .type == "changed") | {locale: $loc, filePath, resourcePath, text: (if .type == "added" then .value else .newValue end)}]')
# Exit early if nothing needs translation
[ "$(echo "$to_translate" | jq 'length')" -eq 0 ] && echo "Nothing to translate" && exit 0
# Step 3: Send strings to Claude API for translation
response=$(curl -s https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d "$(jq -n --arg items "$to_translate" '{
model: "claude-sonnet-4-20250514",
max_tokens: 8192,
messages: [{role: "user", content: "Translate each item to its target locale. Keep placeholders like {name}, {{count}}, %s intact.\n\nReturn JSON array: [{\"locale\": \"...\", \"filePath\": \"...\", \"resourcePath\": \"...\", \"value\": \"<translation>\", \"from\": \"<original>\"}]\n\nItems:\n\($items)"}]
}')")
echo "[DEBUG] API Response: $response"
# Step 4: Extract translated text from Claude's response
# Remove markdown code blocks if present
translated=$(echo "$response" | jq -r '.content[0].text' | sed 's/```json//g; s/```//g')
echo "[DEBUG] Extracted translations: $translated"
# Step 5: Reorganize translations by locale for LocaleOps apply command
# Transform from array to object: {locale: [{filePath, resourcePath, value, from}]}
translations_by_locale=$(echo "$translated" | jq 'group_by(.locale) | map({ (.[0].locale): map({filePath, resourcePath, value, from}) }) | add')
echo "[DEBUG] Grouped by locale: $translations_by_locale"
# Step 6: Apply translations and create PR
npx @localeops/localeops apply "$translations_by_locale"

This workflow applies completed translations to your repository. It’s designed for asynchronous translation workflows where translations are completed by external services, human translators, or APIs.

Workflow:

  1. Triggered via repository_dispatch event
  2. Receives translations in the event payload
  3. Applies translations using LocaleOps
  4. Creates a pull request with the changes

Trigger this workflow using GitHub API:

Terminal window
curl -X POST \
-H "Authorization: token YOUR_GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/OWNER/REPO/dispatches \
-d '{"event_type":"localeops_apply","client_payload":{"translations":{...}}}'

Requirements:

  • GITHUB_TOKEN: Automatically provided by GitHub Actions
localeops.apply.yml
name: apply translations
on:
repository_dispatch:
types: [localeops_apply] # Triggered via repository_dispatch event
# Prevent multiple apply workflows from running simultaneously
concurrency:
group: localeops_apply
cancel-in-progress: false
jobs:
apply_translations:
runs-on: ubuntu-latest
permissions:
contents: write # Required to push commits
pull-requests: write # Required to create pull requests
steps:
- name: checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Configure git for commits created by LocaleOps
- name: configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Extract translations from repository_dispatch payload
# The payload should contain: {translations: {locale: [{filePath, resourcePath, value}]}}
- name: set env vars
run: |
{
echo "TRANSLATIONS<<EOF"
echo '${{ toJson(github.event.client_payload.translations) }}'
echo "EOF"
} >> "$GITHUB_ENV"
# Apply translations to locale files and create PR
- name: run localeops
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub token for creating PR
run: npx @localeops/localeops apply "${TRANSLATIONS}"

This workflow extracts untranslated and changed strings from your locale files. It’s designed for manual or external translation workflows where you want to extract strings without automatically translating them.

Workflow:

  1. Triggered via repository_dispatch event
  2. Extracts new/changed strings using LocaleOps
  3. Outputs the extraction result (can be sent to external service)

The output is a JSON object containing:

  • New strings (type: “added”)
  • Changed strings (type: “changed”)
  • Organized by locale, file path, and resource path

Example output:

{
"es": [
{"type": "added", "filePath": "common.json", "resourcePath": "hello", "value": "Hello"}
]
}

Trigger this workflow using GitHub API:

Terminal window
curl -X POST \
-H "Authorization: token YOUR_GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/OWNER/REPO/dispatches \
-d '{"event_type":"localeops_extract"}'

Use cases:

  • Send extracted strings to a translation agency
  • Export to CSV/Excel for human translators
  • Trigger external translation API
  • Review what needs translation before processing

Requirements:

  • GITHUB_TOKEN: Automatically provided by GitHub Actions
localeops.extract.yml
name: extract strings
on:
repository_dispatch:
types: [localeops_extract] # Triggered via repository_dispatch event
# Prevent multiple extract workflows from running simultaneously
concurrency:
group: localeops_extract
cancel-in-progress: false
jobs:
extract:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
# Extract untranslated strings and output the result
# Note: You can pipe this output to external services or save it as an artifact
- name: extract
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub token for accessing repository
# DEBUG: "true" # (optional) Uncomment to enable debug output
run: |
output=$(npx @localeops/localeops extract)
echo "$output"
# Optional: Save output as artifact for later use
# echo "$output" > extraction-result.json
# Optional: Send to external service
# curl -X POST https://your-translation-service.com/api/translate \
# -H "Content-Type: application/json" \
# -d "$output"