Skip to main content

Endpoint

POST https://i18n.doctor/api/scan
Timeout: 30 seconds (Vercel hobby tier limit) Scans a public GitHub repository to detect locale files, analyze translation coverage, and identify missing keys, untranslated strings, and orphan keys across all supported locales.

Request Body

repo
string
required
GitHub repository URL or shorthand identifier. Accepts the following formats:
  • Full URL: https://github.com/owner/repo
  • Full URL with branch: https://github.com/owner/repo/tree/branch
  • Shorthand: owner/repo
The endpoint will use the default branch if no branch is specified.

Request Example

curl -X POST https://i18n.doctor/api/scan \
  -H "Content-Type: application/json" \
  -d '{
    "repo": "https://github.com/acme/my-app"
  }'
const response = await fetch('https://i18n.doctor/api/scan', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    repo: 'acme/my-app'
  })
});

const data = await response.json();

Response

repo
object
Repository metadata
localeGroup
object
Information about the detected locale file structure
report
object
Comprehensive translation health report

Success Response Example

{
  "repo": {
    "owner": "acme",
    "repo": "my-app",
    "branch": "main",
    "description": "An example multilingual application",
    "stars": 1234
  },
  "localeGroup": {
    "basePath": "locales",
    "style": "flat",
    "locales": ["en", "fr", "es", "de"]
  },
  "report": {
    "sourceLocale": "en",
    "totalSourceKeys": 150,
    "locales": [
      {
        "locale": "es",
        "totalKeys": 120,
        "translatedKeys": 115,
        "missingKeys": ["home.new_feature", "settings.privacy"],
        "untranslatedKeys": ["about.team_size"],
        "orphanKeys": ["old.deprecated_key"],
        "coverage": 77
      },
      {
        "locale": "fr",
        "totalKeys": 148,
        "translatedKeys": 145,
        "missingKeys": ["home.new_feature"],
        "untranslatedKeys": [],
        "orphanKeys": [],
        "coverage": 97
      },
      {
        "locale": "de",
        "totalKeys": 150,
        "translatedKeys": 150,
        "missingKeys": [],
        "untranslatedKeys": [],
        "orphanKeys": [],
        "coverage": 100
      }
    ],
    "summary": {
      "totalLocales": 3,
      "avgCoverage": 91,
      "totalMissing": 3,
      "totalUntranslated": 1,
      "totalOrphan": 1
    }
  }
}

Error Responses

400 Bad Request

Missing or invalid repo field in request body.
{
  "error": "Missing `repo` field"
}

404 Not Found

Repository not found
{
  "error": "Repository not found"
}
No locale files detected Returned when the repository doesn’t contain any recognizable translation files in supported formats (JSON, YAML, PO) or standard directories.
{
  "error": "No locale files found",
  "hint": "We look for JSON/YAML/PO files in directories like locales/, i18n/, messages/, lang/, etc."
}

422 Unprocessable Entity

Source locale could not be parsed or is invalid.
{
  "error": "Source locale \"en\" could not be parsed"
}

429 Too Many Requests

GitHub API rate limit exceeded. This occurs when making too many requests to the GitHub API without authentication.
{
  "error": "GitHub API rate limit exceeded"
}

500 Internal Server Error

General server error or unexpected issue during scanning.
{
  "error": "Internal server error"
}

Supported File Formats

The scanner automatically detects and parses locale files in the following formats:
  • JSON (.json)
  • YAML (.yaml, .yml)
  • Gettext PO (.po)

Supported Directory Patterns

i18n Doctor searches for translation files in common directory structures: Standard directories:
  • locales/, locale/
  • i18n/
  • lang/, languages/
  • translations/
  • messages/
Framework-specific patterns:
  • public/locales/, public/locale/, public/i18n/
  • src/locales/, src/locale/, src/i18n/, src/lang/, src/messages/, src/translations/
  • app/i18n/
  • assets/i18n/, assets/locales/
File structure styles:
Files named with locale codes:
locales/en.json
locales/fr.json
locales/es.json
locales/pt-br.yaml

Use Cases

Check Translation Coverage

Quickly assess how complete your translations are across all supported locales:
const { report } = await scanRepo('myorg/myapp');
console.log(`Average coverage: ${report.summary.avgCoverage}%`);

Identify Missing Keys

Find which translation keys need to be added to specific locales:
const { report } = await scanRepo('myorg/myapp');
const frenchLocale = report.locales.find(l => l.locale === 'fr');
console.log('Missing French translations:', frenchLocale.missingKeys);

Detect Orphan Keys

Clean up unused translation keys that exist in target locales but not in your source:
const { report } = await scanRepo('myorg/myapp');
for (const locale of report.locales) {
  if (locale.orphanKeys.length > 0) {
    console.log(`${locale.locale} has ${locale.orphanKeys.length} orphan keys`);
  }
}

Pre-deployment Validation

Ensure translations meet quality standards before deploying:
const { report } = await scanRepo('myorg/myapp');
const minCoverage = 95;

for (const locale of report.locales) {
  if (locale.coverage < minCoverage) {
    throw new Error(
      `${locale.locale} coverage (${locale.coverage}%) below threshold (${minCoverage}%)`
    );
  }
}

Monitor Translation Health

Track translation quality over time by storing scan results:
const result = await scanRepo('myorg/myapp');
await db.insert({
  timestamp: Date.now(),
  avgCoverage: result.report.summary.avgCoverage,
  totalMissing: result.report.summary.totalMissing,
  locales: result.report.locales
});

Build docs developers (and LLMs) love