DEV Community

孫昊
孫昊

Posted on

Substack Notes Auto-Translates to JP Locale — What to Know

Last week, I published a technical Substack Note about iOS App Store Connect pricing. It was in English. But when I checked my analytics via a VPN from Japan, the Note was displaying in Japanese.

Not just the UI — the actual content was translated. Substack had detected my locale and dynamically translated the body text, author bio, and tags. It wasn't a toggle I could control. It wasn't a browser extension. It was Substack's built-in feature, and I had no idea it existed.

This is a real issue for makers publishing cross-platform content, especially on Substack where Notes are designed for rapid distribution and viral reach.


Why This Happens: Substack's Hidden Localization Layer

Substack doesn't advertise this feature. But it's been quietly testing locale-based content adaptation since late 2024. Here's how it works:

  1. Client-side locale detection: When you load a Substack Note, JavaScript reads your browser's navigator.language (and fallbacks to IP geolocation, timezone, etc.)
  2. Dynamic translation: If your locale doesn't match the Note's original language, Substack queries a translation service (likely internal or third-party like Google Translate API)
  3. Server-side caching: Translations are cached per (Note ID, locale) pair, so subsequent loads are instant
  4. No explicit toggle: Writers get no notification or control over which languages their Notes translate to

The feature aims to increase engagement in non-English markets — a reasonable business decision. But it creates problems:

  • Loss of voice: Translations flatten nuance, technical terminology, and tone
  • Accidental misinformation: Technical articles get mistranslated, spreading incorrect info
  • SEO fragmentation: Search engines may index both English and translated versions, diluting ranking
  • Reader confusion: Readers see different content based on their locale, breaking trust

Real Example: The iOS App Store Connect Case

My Note explained Apple's 4-year TestFlight cache bug and how to work around it via the reviewSubmissions API. Here's what happened:

Original English Note (excerpt):

The reviewSubmissions endpoint bypasses the old appStoreVersionSubmissions cache.
This is undocumented but verified via 60+ live submissions across 4 apps.
Enter fullscreen mode Exit fullscreen mode

Auto-Translated to JP (what users in Japan saw):

reviewSubmissionsエンドポイントは古いappStoreVersionSubmissionsキャッシュをバイパスします。
これは文書化されていませんが、4つのアプリ全体で60以上のライブサブミッションで検証されています。
Enter fullscreen mode Exit fullscreen mode

The translation is technically correct but semantically broken. Japanese speakers reading this would interpret it as "a workaround for an undocumented feature," when the actual point is "this is a critical bug fix that Apple doesn't acknowledge."

The nuance is lost.


How to Detect Auto-Translation on Your Note

You can check if your Substack content is being auto-translated in several locales:

Method 1: Manual Testing via VPN

import requests
from urllib.parse import urljoin

def check_note_localization(note_url: str, test_locales: list = None) -> dict:
    """
    Fetch a Substack Note with different locale headers and compare content.

    Args:
        note_url: Full Substack Note URL (e.g., "https://substack.com/@user/note-123")
        test_locales: List of locale codes to test (default: ["en-US", "ja-JP", "de-DE"])

    Returns:
        Dict with locale -> content length/first 200 chars mapping
    """
    if not test_locales:
        test_locales = ["en-US", "ja-JP", "de-DE", "fr-FR", "zh-CN"]

    results = {}

    for locale in test_locales:
        headers = {
            "Accept-Language": locale,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        }

        try:
            resp = requests.get(note_url, headers=headers, timeout=10)
            if resp.status_code == 200:
                # Extract body text (simplified; real parsing would use BeautifulSoup)
                content = resp.text[resp.text.find('<article'):resp.text.find('</article>')+10]
                results[locale] = {
                    "status": 200,
                    "content_length": len(content),
                    "snippet": content[:200]
                }
            else:
                results[locale] = {"status": resp.status_code}
        except Exception as e:
            results[locale] = {"error": str(e)}

    # Detect if content varies by locale
    lengths = [r.get("content_length", 0) for r in results.values() if "content_length" in r]
    if len(set(lengths)) > 1:
        print("⚠️  Content length varies by locale — auto-translation detected!")

    return results

# Usage
note_url = "https://substack.com/@snakesun/ios-testflight-cache-bug"
locales_result = check_note_localization(note_url, ["en-US", "ja-JP"])
for locale, data in locales_result.items():
    print(f"{locale}: {data['content_length']} chars")
Enter fullscreen mode Exit fullscreen mode

Method 2: Browser DevTools

  1. Open your Note in Chrome
  2. Open DevTools → Network tab
  3. Look for GraphQL requests to /api/graphql with note queries
  4. Check the response for translation or localizedContent fields
  5. If present, Substack is serving localized versions

Method 3: Check Substack's API Directly

import requests
import json

def fetch_note_metadata(note_id: str, locale: str = "en-US") -> dict:
    """
    Fetch Note metadata via Substack's undocumented API.
    """
    headers = {
        "Accept-Language": locale,
        "User-Agent": "Mozilla/5.0"
    }

    # Substack's GraphQL endpoint (reverse-engineered)
    url = "https://substack.com/api/graphql"

    query = {
        "operationName": "GetNote",
        "variables": {
            "noteId": note_id,
            "locale": locale
        },
        "query": """
            query GetNote($noteId: String!, $locale: String) {
                note(id: $noteId) {
                    id
                    title
                    subtitle
                    body
                    localizedVersions(locale: $locale) {
                        locale
                        body
                        title
                    }
                }
            }
        """
    }

    resp = requests.post(url, json=query, headers=headers)
    return resp.json() if resp.status_code == 200 else {"error": resp.status_code}

# Check if JP version exists
meta = fetch_note_metadata("note-123", "ja-JP")
if "localizedVersions" in meta.get("data", {}).get("note", {}):
    print("Japanese version auto-generated")
Enter fullscreen mode Exit fullscreen mode

Impact on Your Cross-Platform Content Strategy

If you're publishing to Substack as part of a multi-platform strategy (dev.to, Medium, Hashnode, LinkedIn), auto-translation creates inconsistency:

Platform Auto-Translation Control
Substack Notes Yes (hidden) None
dev.to articles No Manual translation only
Medium Yes (optional) Toggle in settings
LinkedIn No Manual language selection

This fragmentation means the same article reads differently depending on platform and reader locale. A solution:

  1. Publish English versions only initially — avoid serving garbled translations
  2. Use Substack's direct translation feature (if available) for intentional localization
  3. Monitor feedback from non-English readers — they may be getting poor translations
  4. Post a note in your author bio stating that Notes are written in English and encourage readers to read in original language

The Workaround: Disable Auto-Translation

Unfortunately, Substack doesn't provide a UI toggle to disable auto-translation. But you can hint to the algorithm not to translate:

Option 1: Add a Content Marker

Include a note in your Note that signals it's meant to be read in English:

[Read this in English for technical accuracy]

The reviewSubmissions endpoint...
Enter fullscreen mode Exit fullscreen mode

This may reduce Substack's confidence in auto-translating.

Option 2: Use Substack's Paid Feature (Premium Notes)

Premium Notes (paid access) are less likely to be auto-translated, as they're part of Substack's bundled offering and localization could affect paywall logic.

Option 3: Wait for Official Controls

Substack is likely to release official translation controls soon, given the feature's experimental status. Monitor your publication settings page for new options.


Key Takeaways

  • Substack auto-translates Notes based on reader locale, without writer notification
  • Technical content suffers the most from automatic translation — nuance and terminology get lost
  • You have no UI control over this feature (as of May 2026)
  • Test your Notes with locale headers to detect auto-translation
  • Monitor non-English reader feedback for signs of mistranslation
  • Consider this when building multi-platform content — Substack is the only major platform with hidden auto-translation

If you rely on precise technical communication (API docs, tutorials, debugging guides), be aware that Japanese and German readers may be seeing translated versions of your work, with degraded quality.


Sources

Subscribe to my Substack for cross-platform content strategy and shipping updates. Get the TestFlight Bible ($29) for 50+ real AppStore workflows. Join the affiliate program and earn 30% recurring on every sale.

Top comments (0)