Total unique visitors
Browse by category Chatbots Image Generation Video Generation Audio & Voice Coding Writing Productivity Research AI Agents Free Tier Table
Home page 問問貓說 AI

Ask CatAI Tool SummaryDeepL

DeepL Glossaries for Traditional Chinese (2026): Create With zh, Translate With ZH-HANT — the Variant Code Fails

Article last updated:2026-09-03

The annoying part of machine translation is not awkward phrasing. It is that the same term comes out differently every time — a brand name gets translated instead of kept, a product name gets split, and a technical term alternates between two wordings across a single document. Review time goes into fixing the same handful of words over and over.

DeepL’s answer is the glossary: you declare that a given source term must render as a given target term. Officially, DeepL then flexes those entries for case, gender, tense, and other grammar features where the target language inflects — it is not a blind find-and-replace.

Traditional Chinese, though, has a trap that is spelled out in the documentation and almost never in tutorials: a glossary can only be created with the language code zh. Passing zh-Hant fails. Here is the whole flow.

1. First, confirm Chinese supports glossaries at all

It does. Reading DeepL’s supported-languages table directly (checked 2026-09-03), all three Chinese codes carry the glossary flag:

CodeLanguageGlossary support
ZHChinese (unspecified variant)Yes
ZH-HANTChinese (traditional)Yes
ZH-HANSChinese (simplified)Yes

Most people read that table and immediately try to create a glossary with zh-Hant. That is where it breaks.

2. The trap: root code to create, variant code to translate

DeepL separates root language codes (zh, pt, fr) from variant codes (zh-Hant, pt-BR, fr-CA). The official guide on customizations for variants publishes this table:

Use thisNot this
zhzh-Hant, zh-Hans
ptpt-BR, pt-PT
frfr-CA, fr-CH
dede-CH
eses-ES, es-419

The documented rule: customizations such as glossaries and style rules must be created with the root code, and attempting to create one with a variant code will fail.

So where does the traditional-versus-simplified distinction happen? In the translation request. Create the glossary with zh, then pass target_lang: ZH-HANT when translating — the glossary still applies. DeepL states the same thing for English: a glossary whose target is EN applies when translating into EN-US and EN-GB alike.

In practice, if your traditional and simplified wordings differ, build two glossaries, both with zh as the target language but with different entries, and pass the matching glossary_id depending on whether you are translating into ZH-HANT or ZH-HANS. That is exactly the pattern in DeepL’s own Portuguese example, where two glossaries — one saying “nota fiscal”, one saying “fatura” — are both created with the root code PT.

3. Create your first glossary (v3 endpoints)

Understand the v3 shape first: a glossary holds one or more dictionaries, and each dictionary covers a single language pair in one direction. Want both directions? Add a second, reversed dictionary.

curl -X POST https://api.deepl.com/v3/glossaries \
  --header "Authorization: DeepL-Auth-Key $API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "AMPM Brand Glossary",
    "dictionaries": [
      {
        "source_lang": "en",
        "target_lang": "zh",
        "entries": "prompt\t提示詞\nagent\t代理程式",
        "entries_format": "tsv"
      }
    ]
}'

A success returns 201 with a body like this:

{
  "glossary_id": "def3a26b-3e84-45b3-84ae-0c0aaf3525f7",
  "ready": true,
  "name": "AMPM Brand Glossary",
  "dictionaries": [
    { "source_lang": "en", "target_lang": "zh", "entry_count": 2 }
  ],
  "creation_time": "2025-08-03T14:16:18.329Z"
}

Keep the glossary_id — you need it on every translation call.

If your terminology already lives in a CSV file, the documented approach is to pipe it through jq -Rs so the file contents land in the entries field without hand-escaping.

Note: on a free API key the host is api-free.deepl.com; paid keys use api.deepl.com. That split is stated in DeepL’s getting-started documentation.

4. Using it in a translation — and the second mandatory condition

curl -X POST https://api.deepl.com/v2/translate \
  --header "Authorization: DeepL-Auth-Key $API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "text": ["Write a better prompt for the agent."],
    "source_lang": "EN",
    "target_lang": "ZH-HANT",
    "glossary_id": "def3a26b-3e84-45b3-84ae-0c0aaf3525f7"
}'

Three things to internalise:

  1. source_lang is mandatory. The documentation is blunt: glossaries cannot yet be used with automatic source language detection. If your pipeline relies on auto-detect, this is where it fails — and it fails quietly, with a normal-looking translation and no glossary applied.
  2. Management is v3; translation stays on v2. DeepL states that the v3 endpoints handle glossary management only. Looking for a v3 translate endpoint is a dead end.
  3. The language pair must match the request, and glossary_id cannot be combined with glossary_ids (the array form, capped at five glossaries).

5. Edit, read, delete: PUT and PATCH do not mean the same thing

Editability is v3’s headline advantage — v2 glossaries are immutable, and changing one means deleting and recreating it. But the two editing endpoints behave differently enough that picking the wrong one destroys entries:

MethodScopeBehaviour
PUT /v3/glossaries/{id}/dictionariesOne dictionaryCreates the dictionary for that language pair, or replaces it entirely if it exists
PATCH /v3/glossaries/{id}Whole glossaryUpdates metadata such as the name; entries passed for a language pair are merged into the existing dictionary

The short version: PATCH to add terms (merge), PUT to swap the whole list (replace). Note also that a single PUT or PATCH changes one dictionary — changing the same source phrase across several language pairs means one call per dictionary.

Reading and deleting:

  • GET /v3/glossaries lists every glossary with per-dictionary metadata (no entries)
  • GET /v3/glossaries/{id}/entries returns one dictionary’s entries, selected via the source_lang and target_lang query parameters; currently TSV only
  • DELETE /v3/glossaries/{id} deletes the whole glossary
  • DELETE /v3/glossaries/{id}/dictionaries?source_lang=...&target_lang=... deletes a single dictionary

One compatibility trap worth flagging: DeepL warns against mixing v2 and v3 in the same integration. Once a glossary has been edited via v3, the v2 endpoints can no longer query it correctly, and to prevent data loss, deleting such a glossary through v2 is disabled — you must use the v3 deletion endpoint.

6. Five formatting rules that silently drop entries

This is where real projects break, because a malformed entry usually does not raise an error — the rule simply never applies. From the documented limits:

  1. No duplicate source entries, and neither source nor target may be empty.
  2. No control characters (\t or \n inside a phrase), no Unicode newlines, and no leading or trailing whitespace. Pasting from a spreadsheet is the usual culprit for trailing spaces.
  3. In CSV, fields containing commas or double quotes must be wrapped in double quotes, and a double quote inside a quoted field is escaped by doubling it. TSV is the same, with a tab as the separator.
  4. CSV entries may optionally append source and target language after the phrases — and entries whose languages do not match the dictionary’s pair are ignored. Ignored, not rejected.
  5. Size limits: up to 10 MB of entries per dictionary, so a glossary with five dictionaries holds up to 50 MB; the glossary name and each source and target phrase are capped at 1024 UTF-8 bytes.

7. How many glossaries does an account get?

This is the item second-hand articles most often get wrong, because two unrelated numbers circulate. Both were checked on 2026-09-03:

  • On the API side: the older v2 glossary endpoint spec states that 1,000 glossaries are allowed per account, while the current v3 management guide says only that the number of glossaries per account is limited by your plan, linking back to the official API plan page.
  • On the DeepL Translator (web and app) side: the official plan page, read as plain text on 2026-09-03, shows the free version at 50,000 characters per month and 1 glossary; Individual at 300,000 characters per month and 1 glossary; Team at 1,000,000 characters per user per month and 5 glossaries; Business and Enterprise listed as unlimited glossaries.

These are separate allowances. A Translator plan’s glossary count says nothing about what an API key may create. If you are building on the API, the API plan is the one that governs.

8. What this article does not pin down

  • Current API plan tiers (Free / Developer / Growth): character allowances, monthly price, and glossary caps. DeepL’s API pricing block is dynamically rendered, and this round’s plain-text read did not return any price figures, so no API prices appear above — all marked unverified. Our own tool page carries a second-hand, unconfirmed note (that API Free and API Pro stopped being sold from July 2026 in favour of Developer or Growth); until a first-hand view of the pricing page confirms it, treat that as a lead, not a fact.
  • The exact number of glossary-capable languages. The v2 endpoint spec’s prose list and the current supported-languages table do not fully agree (the former’s list mentions Thai, the latter’s glossary flag does not cover it). This article uses only the per-language support flags and does not commit to a total.
  • Whether free API keys are still open to new sign-ups. A “Free API Key” registration link (productId=api-developer) is still present on the official API page, but we did not complete a sign-up to verify it, so we make no claim that one can still be obtained.

9. The order of operations that works

  1. Check your language in the supported-languages table and take its root code (Traditional Chinese: zh).
  2. Create the glossary with POST /v3/glossaries, target language set to the root code, and store the glossary_id.
  3. Only at translation time do you pass target_lang: ZH-HANTand always include source_lang.
  4. Verify with a real sentence containing the term. If nothing changed, the cause is usually a missing source_lang or a trailing space in an entry.
  5. Afterwards, PATCH to add terms, PUT to replace a list, and keep the whole project on v3 rather than mixing versions.

What Amo and Pimi think

AMO Amo Finding faults
This time I want to raise something more important to readers first — the official pricing page loads dynamically, and neither WebFetch nor the r.jina.ai proxy can read the pricing block, so every price here is secondhand. Worse, the sources contradict each other: one calls it Individual US$8.74/month, another calls it Starter US$10.49/month — the plan names and amounts don't even match. API Free and API Pro merged starting July 2026, and the official site doesn't explain how existing users are supposed to migrate. With data quality like this, you really need to confirm everything on the official site yourself before paying.
PIMI Pimi Advantages
But its translation quality is widely regarded as the most natural among AI translators, and Traditional Chinese support is complete — nobody can deny that. The free plan gives 50,000 characters a month plus 1 document translation, which is plenty for personal users. It can translate Word and PDF files directly while keeping the formatting, which a lot of competitors can't do. Chinese support is full, and the API Growth plan at US$26/month includes 12 million characters a year — a reasonable barrier to entry for developers, and it's payable by credit card too.
So, do you need to pay or not?

If you need high translation quality and want to preserve document formatting, try the free version's 50,000 characters first. But we couldn't confirm the paid plan prices firsthand — sources contradict each other — so before subscribing, be sure to check the current plans and prices on the official site yourself.

Let's take a look at these

Go to the official website

Affiliate Links Notice