ShipAgent

Languages

The eight built-in languages, how missing translations fall back to English, adding a ninth language, and asking the agent to translate.

The site ships in eight languages. English is the default and the source every other language is checked against.

Code Language URL
en English /pricing (no prefix)
zh 中文 /zh/pricing
ja 日本語 /ja/pricing
fr Français /fr/pricing
de Deutsch /de/pricing
ko 한국어 /ko/pricing
es Español /es/pricing
it Italiano /it/pricing

The list lives in i18n/routing.ts (LOCALES). English has no prefix in the URL; every other language has its code. The sitemap and the hreflang tags on each page list every language automatically.

Visitors pick a language with the switcher in the header. If you set NEXT_PUBLIC_LOCALE_DETECTION=true, first-time visitors are also sent to the language their browser asks for.

Where the text lives

What Where
Page and interface text i18n/messages/<code>/, one JSON file per page or area (Landing.json, Pricing.json, Dashboard/Admin/Blogs.json …); common.json holds the header, footer, login and shared text
Plan names, descriptions and features config/pricing.ts, inside each plan's copy
The About page content/about/<code>.mdx
Blog posts written as files blogs/<code>/*.mdx
Blog and glossary posts written in the admin the database, one post per language (see Blog and glossary)
Social preview images public/og.png for English, public/og_<code>.png for the others

Missing text falls back to English, key by key

i18n/request.ts loads the English file first and lays the translation over it. Any key the translation lacks, or leaves empty, shows the English text. A whole missing file shows English for that page. A list (for example the features on the landing page) is taken from the translation only when it has as many items as the English one; otherwise the English list shows.

So a half-translated language never breaks a page; it shows some English. The same holds for plan text: a plan without copy.<code> shows its English text.

Asking the agent to translate

The agent writes every language itself. Useful requests:

I changed the hero text in i18n/messages/en/Landing.json.
Update the same keys in the other seven languages, each written in its own language.
Check every language folder against English and translate any key that is missing or still in English.
Translate the card text of the new "pro-monthly" plan in config/pricing.ts into every language in LOCALES.

Name the source of truth (usually the English file) and ask for "written in its own language", not word-for-word translation. Have a native speaker read the pages that sell (landing, pricing) before launch.

For blog and glossary posts there is also a translate button in the admin editor; see Blog and glossary.

Adding a language

Tell the agent: "Add Portuguese (pt) as a ninth language." It works through this list:

  1. i18n/routing.ts: add the code to LOCALES and one entry to each table below it: LOCALE_NAMES (the language's own name, shown in the switcher), SHORT_LOCALE_NAMES, LOCALE_ENGLISH_NAMES (used when telling an AI model which language to write), LOCALE_TO_HREFLANG (for example pt-BR).
  2. proxy.ts: the locale list in the matcher (the line '/(en|zh|ja)/:path*'); the file's header asks to keep it in step with LOCALES.
  3. i18n/messages/pt/: a copy of the en/ folder, translated. Anything left out shows English.
  4. config/pricing.ts: a pt entry in each plan's copy.
  5. content/about/pt.mdx: the About page.
  6. public/og_pt.png: the social preview image for that language. The starter ships og.png, og_zh.png and og_ja.png only, so the other languages point to an image that does not exist until you add it.
  7. Optional: blogs/pt/ for file-based posts.

Then it runs pnpm lint and opens a few pages under /pt/.

To remove a language, do the same in reverse. Pages already indexed by search engines in that language will answer 404.

When it fails

What you see Cause Fix
A page shows English in another language the key or the file is missing in that language ask the agent to translate the missing keys
A list shows in English while the rest is translated the translated list has a different number of items make the lists the same length
/pt/… answers 404 for every page the code is missing from LOCALES add it in i18n/routing.ts
A new page's text shows as raw keys (Landing.title) in every language its message file is not registered in the FILES table of i18n/request.ts the agent registers it
The About page is empty in one language content/about/<code>.mdx is missing add the file
Shared links in one language show no preview image public/og_<code>.png is missing add the image