CI/CD
CI pipelines
Any CI that can run a shell can push the source language on merge and pull every language before a release build.
What you get
Source in on merge, every language out before the build.
Scriptable from the CLI
Push, pull and sync from a terminal, a build phase or a coding agent's shell, with a token in the environment.
The CLIEverything is an HTTP call
Project tokens carry read, push and manage scopes, so a CI token that pushes files cannot delete keys.
The HTTP APIPulls on every build
A Run Script phase above Compile Sources keeps the target on the latest verified text without anyone remembering to sync.
Xcode build phaseUpdates over the air
Publish the verified strings and let the running app fetch them, so a fixed translation reaches users without a store release.
Over-the-air delivery
Set it up
From nothing to every language.
Step 1: Store the token as a secret
Two tokens keep the rights apart: one with push for the job that writes source files, one with read for the job that pulls.
Step 2: Push the source on merge to main
A GitHub Actions job; the same two lines work on GitLab, Bitbucket or Jenkins.
.github/workflows/localization.ymlon: push: branches: [main] jobs: push-source: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | curl -fsS -X POST "https://anylocale.com/api/loc/push?project=my-app&format=xcstrings" \ -H "Authorization: Bearer $ANYLOCALE_TOKEN" \ --data-binary @Localizable.xcstrings env: ANYLOCALE_TOKEN: ${{ secrets.ANYLOCALE_PUSH_TOKEN }}Step 3: Pull before the release build
A second job with the read token. The installer lands in ~/.local/bin on a runner without write access to /usr/local/bin, so PATH is extended in the same step; the build that follows picks the files up.
.github/workflows/release.ymljobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v4 - run: | curl -fsSL https://anylocale.com/install.sh | sh export PATH="$HOME/.local/bin:$PATH" anylocale sync --project my-app --platform ios --out-dir Sources/Resources env: ANYLOCALE_TOKEN: ${{ secrets.ANYLOCALE_READ_TOKEN }} - run: xcodebuild -scheme MyApp -configuration Release
Good to know
- The installer writes to ~/.local/bin on a runner without write access to /usr/local/bin; add it to PATH in the same step.
- Exit code 2 means a request or download failed; let it fail the job.
Questions
- Why two tokens?
- So the rights stay apart: the job that pushes source files gets push, the job that pulls before a build gets read. Neither can delete a key.
- What happens when a download fails?
- The CLI exits with code 2 and no half-written file is left behind. Let it fail the job; a build on stale text is the worse outcome.
- Which CI systems work?
- Any that can run a shell. The examples are GitHub Actions; the same two lines work on GitLab, Bitbucket, Jenkins or a Mac mini under a desk.
Start with the file your app already ships.
After checkout, import one strings file and read the first drafts within minutes.
Nothing to connect and nothing to install. The CLI is optional.