A GitHub Action that opens machine-translated pull requests for resource files
in your repository β without retranslating your entire catalog every time one
string changes. Choose one translation provider per run β Azure AI
Translator (default), AWS Translate, or Google Cloud Translation β behind
a single, unified API surface. Each provider is driven by its official SDK
(@azure-rest/ai-translation-text,
@aws-sdk/client-translate,
@google-cloud/translate),
with built-in retry/throttling β no hand-rolled HTTP clients.
Note
Fully backward compatible. provider defaults to azure, so existing
workflows keep working unchanged β no edits required.
Supported formats: .resx, .xliff, .po, .json, .ini, .restext.
Translate the diff, not the catalog. Smart change detection is on by default
and provider independent. The action keeps a compact, deterministic state
manifest at .github/resource-translator-state.json and uses parser keys plus
source-value hashes to translate only keys that are new, missing from a target
file, changed in the source locale, or affected by translation-setting changes.
Unchanged target values are reused, manual target-file edits are preserved, and
every decision is logged with audit-friendly rule codes.
Commit the state manifest so future runs have a reliable baseline. Set
changeDetection: disabled (or false) to restore the legacy behavior of
translating every eligible key on every run, or set statePath to move the
manifest.
If you already have localized target files and want to avoid the initial full
retranslation, run once with snapshotOnly: true. Snapshot mode does not call
Azure, AWS, or Google and does not write target resource files; it creates the
state manifest from existing source/target files, then future smart runs only
translate changed or missing keys.
Everything lives on the docs site: ievangelist.github.io/resource-translator
- π Getting started
- π Translation providers β Azure, AWS, and Google setup
- βοΈ Configuration β repo config, glossary, tone & industry
- π§Ύ Inputs & outputs
- π File formats
- π³ Recipes
- β FAQ
name: translate
on:
push:
branches: [main]
paths:
- "**/*.en.resx"
- "**/*.en.json"
permissions:
contents: write
pull-requests: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: translator
uses: IEvangelist/resource-translator@v3
with:
sourceLocale: en
provider: |
azure:
subscriptionKey: ${{ secrets.AZURE_TRANSLATOR_SUBSCRIPTION_KEY }}
endpoint: ${{ secrets.AZURE_TRANSLATOR_ENDPOINT }}
region: ${{ secrets.AZURE_TRANSLATOR_REGION }}
toLocales: '["es","fr","de"]'
- if: steps.translator.outputs.has-new-translations == 'true'
uses: peter-evans/create-pull-request@v7
with:
branch: machine-translation
title: ${{ steps.translator.outputs.summary-title }}
body: ${{ steps.translator.outputs.summary-details }}
labels: localizationFor all inputs, repo config, glossary, tone/industry control, and recipes, see the full docs.
Pick one provider per run via the provider input (defaults to azure).
For cleaner workflows, provider can be a nested YAML block with that
provider's credentials and native behavior settings; the older flat inputs still
work and override values inside the block. The
providers docs
include dedicated Azure, AWS, and Google sections with links to the official
vendor docs.
| Provider | provider value |
SDK | Credentials |
|---|---|---|---|
| Azure AI Translator | azure (default) |
@azure-rest/ai-translation-text |
subscriptionKey, endpoint, region? |
| AWS Translate | aws |
@aws-sdk/client-translate |
OIDC/default chain, or awsAccessKeyId + awsSecretAccessKey; awsRegion |
| Google Cloud Translation | google |
@google-cloud/translate |
googleApiKey or googleCredentials (service-account JSON) |
Important
Locale codes differ per provider (e.g. Simplified Chinese is zh-Hans on
Azure, zh on AWS, zh-CN on Google). Codes pass through as-is and drive the
output file names, so pick toLocales values your chosen provider supports.
permissions:
id-token: write # for aws-actions/configure-aws-credentials OIDC
contents: write
pull-requests: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/gh-actions-translate
aws-region: us-east-1
- id: translator
uses: IEvangelist/resource-translator@v3
with:
provider: |
aws:
region: us-east-1 # or rely on AWS_REGION from the step above
formality: FORMAL
brevity: true
sourceLocale: en
toLocales: '["es","fr","de"]'To use static keys instead of OIDC, drop the configure-aws-credentials step and
add accessKeyId / secretAccessKey (via secrets) to the nested aws block, or
use the equivalent flat inputs.
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: translator
uses: IEvangelist/resource-translator@v3
with:
provider: |
google:
# Provide EITHER a service-account JSON credential...
credentials: ${{ secrets.GCP_TRANSLATE_CREDENTIALS }}
# ...OR an API key:
# apiKey: ${{ secrets.GCP_TRANSLATE_API_KEY }}
model: nmt
sourceLocale: en
toLocales: '["es","fr","de"]'Provider-specific intent specifiers are mapped where an equivalent exists:
textType β Google format; profanityAction (Marked/Deleted) β AWS
profanity masking. categoryId, apiVersion, profanityMarker, and
allowFallback are Azure-only and ignored by the other providers.
Provider-native knobs are also available: AWS supports formality, brevity,
terminologyNames, and parallelDataNames; Google supports model,
apiEndpoint, and autoRetry.
- π Changelog
- π Security policy
- π€ Contributing
- π Code of conduct
Thanks goes to these wonderful people (emoji key):
vs-savelich π» |
Yevgen Nykytenko π |
Peter Rekdal Khan-Sunde π |
Tim Heuer π π€ π |
Tibor Tompa π€ |
Matteo π» |
Jeffrey T. Fritz π |
This project follows the all-contributors specification. Contributions of any kind welcome!