GitHub - i18n-actions/ai-i18n: ai-i18n is a GitHub Action that translates your app's i18n files using LLMs. It extracts strings, translates only what's changed, and commits the results back to your repo. Works with your LLM provider (Anthropic, OpenAI, Ollama) and multiple i18n formats (XLIFF, JSON). A drop-in replacement for Lokalise, Phrase, and Crowdin.

3 min read Original article ↗

i18n Translate Action

A GitHub Action that automatically translates i18n files using LLM providers (Anthropic Claude, OpenAI GPT, or Ollama).

Features

  • Multiple LLM Providers: Support for Anthropic Claude, OpenAI GPT, and local Ollama models
  • Multiple Formats: XLIFF 1.2, XLIFF 2.0, JSON (flat and nested)
  • ICU Message Format: Intelligent handling of plurals with CLDR rules for 20+ languages
  • Change Detection: Only translates new or modified strings using content hashing
  • Rate Limiting: Built-in rate limiting and retry logic for API calls
  • Batch Processing: Efficient batching of translation requests
  • Git Integration: Automatic commits of translated files

Quick Start

name: Translate i18n files

on:
  push:
    branches: [main]
    paths:
      - 'locales/en/**'

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Translate
        uses: your-org/i18n-translate-action@v1
        with:
          provider: anthropic
          api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          source-language: en
          target-languages: de,fr,es
          files: 'locales/en/**/*.json'

Inputs

Input Description Required Default
provider LLM provider (anthropic, openai, ollama) Yes anthropic
api-key API key for the provider No* -
model Model to use No Provider default
source-language Source language code Yes en
target-languages Comma-separated target language codes Yes -
files Glob pattern for translation files Yes **/*.xliff
format File format (xliff-1.2, xliff-2.0, json-flat, json-nested, auto) No auto
config-file Path to configuration file No .i18n-translate.yml
commit Whether to commit changes No true
commit-message Commit message No chore(i18n): update translations
batch-size Strings per API call No 10
max-retries Maximum retry attempts No 3
ollama-url Ollama server URL No http://localhost:11434
dry-run Run without making changes No false
context Additional context for translations No -

*API key is required for Anthropic and OpenAI providers.

Outputs

Output Description
translated-count Number of strings translated
files-updated Number of files updated
report Translation report in markdown
commit-sha SHA of the commit (if committed)

Configuration File

You can use a .i18n-translate.yml file for configuration:

provider:
  name: anthropic
  model: claude-3-haiku-20240307
  temperature: 0.3

translation:
  batchSize: 15
  maxRetries: 3
  context: "Mobile app UI translations"
  preserveFormatting: true
  preservePlaceholders: true

git:
  enabled: true
  commitMessage: "chore(i18n): update translations"

files:
  pattern: "locales/**/*.json"
  format: json-nested
  sourceLanguage: en
  targetLanguages:
    - de
    - fr
    - es
    - ja
  exclude:
    - "**/node_modules/**"

Supported File Formats

XLIFF 1.2

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" target-language="de">
    <body>
      <trans-unit id="greeting">
        <source>Hello, World!</source>
        <target></target>
      </trans-unit>
    </body>
  </file>
</xliff>

XLIFF 2.0

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="2.0" srcLang="en" trgLang="de" xmlns="urn:oasis:names:tc:xliff:document:2.0">
  <file id="messages">
    <unit id="greeting">
      <segment>
        <source>Hello, World!</source>
        <target></target>
      </segment>
    </unit>
  </file>
</xliff>

JSON (Flat)

{
  "greeting": "Hello, World!",
  "button.save": "Save"
}

JSON (Nested)

{
  "greeting": "Hello, World!",
  "button": {
    "save": "Save",
    "cancel": "Cancel"
  }
}

ICU Message Format Support

The action intelligently handles ICU MessageFormat patterns, including plurals:

{
  "items_count": "{count, plural, one {# item} other {# items}}"
}

When translating to languages with different plural rules (like Russian, Arabic, or Polish), the action automatically generates the correct plural forms based on CLDR rules.

Supported Plural Rules

  • Simple (one/other): English, German, Spanish, etc.
  • Complex (one/few/many/other): Russian, Polish, Ukrainian, Czech
  • Full (zero/one/two/few/many/other): Arabic
  • None (other only): Japanese, Chinese, Korean

Provider Configuration

Anthropic Claude

- uses: your-org/i18n-translate-action@v1
  with:
    provider: anthropic
    api-key: ${{ secrets.ANTHROPIC_API_KEY }}
    model: claude-3-haiku-20240307  # or claude-3-sonnet, claude-3-opus

OpenAI GPT

- uses: your-org/i18n-translate-action@v1
  with:
    provider: openai
    api-key: ${{ secrets.OPENAI_API_KEY }}
    model: gpt-4o-mini  # or gpt-4o, gpt-4-turbo

Ollama (Self-hosted)

- uses: your-org/i18n-translate-action@v1
  with:
    provider: ollama
    model: llama3.2
    ollama-url: http://localhost:11434

Preventing Infinite Loops

The action automatically detects and skips runs triggered by its own commits. You can also use skip markers:

commit-message: "chore(i18n): update translations [skip i18n]"

Development

Prerequisites

  • Node.js 20.x
  • npm

Setup

Build

Test

Lint

License

MIT