How to Count Words in a Translation Pair Correctly (2026)
The source and target of a translation pair almost never have the same word count. Here's how to count both sides correctly, including CJK, in 2026.
How to Count Words in a Translation Pair Correctly
Paste the English source and its French translation into two word counters and you get two different numbers. That is not a bug — it is how languages work. A translation pair almost never matches word for word, and if you count it wrong (by splitting Chinese on spaces, say) the gap gets worse. This guide covers how to count both sides accurately, why the numbers diverge, and how to turn the ratio into a quality signal.
TL;DR
- Source and target word counts differ by design; a mismatch is normal.
- English usually expands 20–35% into European languages; short strings expand far more.
- Never split CJK text on spaces — use
Intl.Segmenterwith word granularity. - Bill on source count for a price both sides can agree before work starts.
- Track the source-to-target ratio to flag skipped or padded segments.
Why source and target word counts never match
The first thing to accept is that a translation pair is two texts of different lengths carrying the same meaning. Expecting them to have equal word counts is like expecting a sentence and its paraphrase to be identical — the information is preserved, the packaging is not.
How much does text expand from English to other languages?
English is unusually compact, so most translations out of it grow. Full paragraphs into French, Spanish, or Italian tend to add 20–30%, and German can run higher because of its compound nouns. The W3C's guide to text size in translation collects average expansion rates originally published in IBM's global-design guidelines, and the pattern is clear: the shorter the source, the bigger the swing.
| English source length | Average expansion |
|---|---|
| Up to 10 characters | 200–300% |
| 11–30 characters | 160–200% |
| 31–70 characters | 140–170% |
| Over 70 characters | ~130% |
Contraction is real too. Translating English into Finnish can shave off 25–30%, so a target that is shorter than its source is not automatically missing content.
Why the shorter the string, the bigger the expansion
A ten-character UI label has almost no room to average out. One long compound word in German or one multi-word gloss in Portuguese can double or triple its length, and there is no surrounding text to dilute the effect. Per the W3C article, Flickr's short label "views" renders roughly three times longer in Italian ("visualizzazioni"). Across a 500-word paragraph, those spikes cancel out and the ratio settles near the averages above. This is why counting a whole document gives a stabler ratio than counting a single button.
Source-count vs target-count billing
Because the two counts differ, translators and agencies have to pick one to price on:
- Source count is known before the job starts, so both sides can lock a fixed price and neither can game it.
- Target count is only knowable once the translation exists, so the client can't verify the quote up front, and it quietly rewards padding.
- Per-character pricing is standard for CJK source text, where "words" are ambiguous (more on that below).
Most agencies quote on the source count for predictability. Whichever you choose, count it with a tool that treats the language correctly — which is where naive counters fall down.
How to count words in a translation pair correctly
Counting the English side is easy: words are space-delimited, so text.trim().split(/\s+/).length is close enough. The target side is where it gets interesting, because "split on whitespace" is a rule that only holds for some languages.
Count both sides, then compare the ratio
The workflow is straightforward. Count the source, count the target, and divide. Paste each side into iKit's Word Counter to get live word, character, and reading-time numbers without uploading anything, then read the ratio:
- Ratio near the expected range (say 1.2–1.35 for English→German) — healthy.
- Ratio near 1.0 on an expanding pair — a segment may be untranslated or copy-pasted.
- Ratio far above expected — possible padding, doubled text, or duplicated segments.
The ratio is a cheap, language-agnostic QA signal, but only if both counts are measured with the same, correct method.
Why splitting on spaces breaks CJK word counts
Chinese, Japanese, Thai, Khmer, and several other scripts don't put spaces between words. Feed one of them to a space-splitter and it returns a count of one, no matter how long the sentence is. As MDN notes on String.prototype.split, this "would not get the correct result if the locale of the text does not use whitespaces between words." Here's the failure in action:
const jp = "吾輩は猫である。名前はたぬき。";
jp.split(/\s+/).length;
// 1 — the entire two-sentence
// string counts as one "word"
A single word for two full sentences is obviously wrong, and it corrupts any ratio you build on top of it. The fix is a segmenter that knows real word boundaries.
Using Intl.Segmenter to count words in any language
Every current browser ships Intl.Segmenter, which applies the Unicode text-segmentation rules in UAX #29 to find word boundaries per locale. Per MDN, it reached Baseline "newly available" status in April 2024, so it works across the latest browsers without a library. Pass granularity: "word" and count only the segments flagged isWordLike to skip spaces and punctuation:
function countWords(text, locale) {
const seg = new Intl.Segmenter(locale, {
granularity: "word",
});
let n = 0;
for (const s of seg.segment(text)) {
if (s.isWordLike) n++;
}
return n;
}
countWords("吾輩は猫である。", "ja"); // 4
countWords("The cat has no name.", "en"); // 5
The same function counts English, Japanese, Thai, and Arabic correctly because the segmenter switches rules based on the locale you pass. That is the whole trick to counting a translation pair: count each side with its own locale, not with one hard-coded splitter.
How to count Chinese, Japanese, and Korean words
CJK deserves its own section because "word count" is a slippery term there, and getting it wrong is the single most common mistake in translation-pair counting.
Characters vs words in CJK
In Chinese there are no spaces and a "word" may be one, two, or three characters. Because of this ambiguity, the industry frequently prices CJK source text per character rather than per word. When you do need a word count — for a translation ratio, for instance — a segmenter gives a defensible number, but always record whether you are comparing words to words or characters to characters. Mixing units is how a healthy pair looks broken.
The isWordLike flag and punctuation
Intl.Segmenter returns every segment, including spaces and punctuation, each tagged with an isWordLike boolean. Counting without that filter inflates the total, because "。" and "、" become "words." Always gate on isWordLike, as in the snippet above. This is also why a segmenter beats a regex like /\p{L}+/u for prose: it understands that "たぬき" is one word, not three loose letters.
Per-character pricing for CJK source text
If a job is quoted per character, count characters with awareness of what a "character" is. str.length counts UTF-16 code units, so an emoji or a rare CJK ideograph outside the Basic Multilingual Plane counts as two. For visible-character counts, iterate with the spread operator ([...str].length) or a grapheme segmenter. We cover this trap in detail in the emoji-length article linked below; for translation billing, agree the counting method in writing before the project starts.
Building a translation word-count workflow
Counting is one step; wiring it into a repeatable review process is what saves time on real projects.
Word-count ratio as a QA signal
Store the source and target counts for every file and compute the ratio. When a batch of Spanish files all sit around 1.25 and one comes back at 0.98, that outlier is worth a look before delivery — it usually means a segment was left in English or a paragraph was dropped. The ratio won't tell you what changed, only that something is off; pair it with a Diff Checker to see the exact words an editor touched inside each segment.
Counting words in JSON and XLIFF localization files
Modern localization rarely ships as plain prose. Strings live in JSON i18n bundles, XLIFF, or .po files, mixed with keys and markup you don't want to count. Before counting, extract just the translatable values — for a JSON language file, validate and inspect it in a JSON Decoder so you count "Welcome back" and not the "greeting.header" key. Counting the raw file inflates every number and ruins the ratio.
Keeping confidential source strings in the browser
Translation source text is often under NDA: unreleased product copy, marketing that hasn't launched, legal wording. Pasting it into a server-side counter sends both the source and the target to someone else's host. Every iKit tool runs entirely in your browser with no upload, so the word counting, diffing, and JSON inspection all happen locally. For pre-launch or client-confidential material, that is not a nice-to-have — it is the difference between a safe workflow and a leak.
References
- Text size in translation — W3C Internationalization — source of the English-to-European expansion rates and the short-string spike examples.
- Intl.Segmenter — MDN Web Docs — API used for locale-aware word counting; Baseline 2024 status and the CJK segmentation example.
- UAX #29: Unicode Text Segmentation — the word-boundary rules that segmenters implement across scripts.
Related on iKit
- Live word, character, and reading-time counts in one panel — the general word-counting workflow behind the source/target counts in this guide.
- How to count Chinese, Japanese, and Korean words correctly — a deeper dive into CJK segmentation and why space-splitting fails.
- A word-level diff workflow for reviewing translation pairs — once the ratio flags a file, this shows which words actually changed.
- Why str.length lies about emoji length in JavaScript — the UTF-16 code-unit trap behind per-character CJK pricing.
- iKit Word Counter vs MS Word's count: when the browser wins — why two tools report different counts for the same text.
Related posts
How to Hit a 1,000-Word Target Without Padding (2026)
Need to hit a 1,000-word target without padding? Plan the structure, budget each section, and reach the count with writing that earns every word.
Reading Time vs Speaking Time: Sizing a Talk (2026)
Reading time and speaking time are not the same number. Here is how to estimate how long a talk runs from a script, using real 2026 words-per-minute rates.
SEO Title & Meta Description Length: 2026 Cheatsheet
The 2026 rules for SEO title and meta description length: real pixel limits, the 50–60 character target, and why Google rewrites your titles.