Soft launch Dialecto is still in testing, and details on this site may change as we finish it.

Scanning & CI

A scan is how your repo’s current state reaches Dialecto: the surgical slice, which is your catalog files plus optional usage snippets. There are two ways for it to arrive. By default the Dialecto GitHub App reads your translation files itself, at the paths you confirmed, and nothing needs wiring. If you block read access on a project, or you want usage snippets (which only your CI can send), the scan runs on your infrastructure as one documented HTTP call, simple enough to wire into any CI in a few lines. This page is that contract. A packaged GitHub Action for it is planned but does not exist yet.

The request

POST /api/repos/:repo_id/scans
Authorization: Bearer <scan token>
Content-Type: application/json

The scan token is per-repo, shown once at creation, stored only as a hash, and regenerable from the repo’s settings. It authorizes scanning — nothing else.

Payload

FieldRequiredDescription
gitShayesthe commit the scan describes
gitBranchyesthe branch — scans are branch-aware
checksumyesidempotency key; resending the same checksum is a no-op
templatesyesarray of {path, content} — your translation files (.po/.pot, or .json for a JSON project), verbatim bytes
gettextUsagesnoarray of {file, content, start_line, end_line} — source snippets around gettext calls

Paths must be relative paths inside the repository (no ..) that match the project’s confirmed translation file paths; locale, domain, and template-vs-catalog are derived from the path. For a Phoenix app that means sending priv/gettext/** as-is after mix gettext.extract --merge. JSON projects send their catalog files the same way; the JSON guide covers what is different, including the Astro add-on that sends where your code reads each key.

Limits: 1,000 template files, 5 MB per file, 10 MB request body, 50,000 usage snippets.

Responses

StatusMeaning
201ingested — body includes entry/usage counts
200idempotent replay (same checksum), nothing changed
401bad or missing scan token
413over a size limit
422a template failed to parse — the whole scan is rejected, nothing partial is stored

Parsing is strict on purpose: one malformed catalog rejects the scan, so the index never holds a half-truth. Validate with msgfmt --check locally if a 422 surprises you.

Asking what to scan

GET /api/repos/:repo_id/scan-config
Authorization: Bearer <scan token>

returns {scan_mode, branch_regex, tracked_branches} — so a CI job can decide cheaply whether the current branch should scan at all. scan_mode is a repo setting: selected (default — the branches you track) or all (with an optional branch regex filter).

What a scan triggers

Ingesting a scan fans out the follow-up work automatically: translation-memory capture from newly translated strings, re-publishing the merge gate and quality checks on affected PRs, and — if the repo opted in — the auto-translate pass over newly untranslated strings.

A CI recipe

Any CI works; the job is: check out, extract, build the payload, POST. As a GitHub Actions sketch using only git, jq and curl, which the runner image already has (adjust the paths to your catalogs):

- uses: actions/checkout@v6
- run: mix gettext.extract --merge
- name: Send the scan
  env:
    DIALECTO_SCAN_TOKEN: ${{ secrets.DIALECTO_SCAN_TOKEN }}
    DIALECTO_URL: https://app.dialecto.eu
    DIALECTO_REPO: "<your repo id>"
  run: |
    set -euo pipefail
    paths=(':(glob)priv/gettext/**/*.po' ':(glob)priv/gettext/**/*.pot')
    git ls-files -z -- "${paths[@]}" | while IFS= read -r -d '' file; do
      jq -cn --arg path "$file" --rawfile content "$file" \
        '{path: $path, content: $content}'
    done > "$RUNNER_TEMP/templates.jsonl"
    checksum=$({ printf '%s\n%s\n' "$GITHUB_SHA" "$GITHUB_REF_NAME"; \
      git ls-files -s -- "${paths[@]}"; } | sha256sum | cut -d' ' -f1)
    jq -s --arg sha "$GITHUB_SHA" --arg branch "$GITHUB_REF_NAME" \
      --arg checksum "$checksum" \
      '{gitSha: $sha, gitBranch: $branch, checksum: $checksum, templates: .}' \
      "$RUNNER_TEMP/templates.jsonl" > "$RUNNER_TEMP/scan.json"
    curl -sS --fail-with-body --retry 3 -X POST \
      -H "Authorization: Bearer $DIALECTO_SCAN_TOKEN" \
      -H "Content-Type: application/json" \
      --data-binary "@$RUNNER_TEMP/scan.json" \
      "$DIALECTO_URL/api/repos/$DIALECTO_REPO/scans"

The checksum covers the commit, the branch and every sent file’s blob id, so a re-run is a no-op and a revert still counts as a new scan. app.dialecto.eu is the address the app will have when it opens; until then, early-access accounts are told the address to use. If you run Dialecto yourself, use your own host.

Rate limiting applies to the API (HTTP 429 with a retry-after header); one scan per push is the intended cadence.

The source-rewrite action

Separate from scanning: when a Dialecto PR carries call-site rewrites, a repo-side action applies them against your working tree, touching only the rewrites listed in the PR. Dialecto computes those rewrites today. The action, dialecto-eu/source-rewrite, is public on GitHub at github.com/dialecto-eu/source-rewrite. Reference it as dialecto-eu/source-rewrite@v1, or pin it to a release commit. In a repository without the action, the PR lists every call site as a manual follow-up instead.