This page describes the end-to-end system TypeScript uses to define, generate, and deliver localized diagnostic messages to users. It covers the JSON source file, the code-generation pipeline, the LCL translation file format, the 13 supported target languages, and how the compiler selects and formats messages at runtime.
For information on how diagnostics are created and attached to AST nodes during compilation, see the Type Checker page (2.3) and Program and Compilation page (2.5). For how tsserver sends diagnostics to editors, see the tsserver Protocol page (5.1).
diagnosticMessages.jsonAll diagnostic message text, category, and numeric code are defined in a single file:
src/compiler/diagnosticMessages.json
Each entry maps an English message string (the human-readable text) to a category and a numeric code:
| Field | Values | Description |
|---|---|---|
| Key (JSON object key) | English string | Human-readable message, may contain {0}, {1}, … placeholders |
category | "Error", "Warning", "Suggestion", "Message" | Severity level |
code | Integer | Stable numeric identifier shown to users (e.g. TS2322) |
Placeholders {0}, {1}, etc. are substituted at the call site with runtime values (type names, identifiers, etc.).
Sources: src/compiler/diagnosticMessages.json1-50
The diagnosticMessages.json file is not used directly at runtime. A build task transforms it into two derived artifacts.
Build task: generate-diagnostics (invoked via the hereby task runner, also run by the post-checkout git hook — see 10.3).
Script: scripts/processDiagnosticMessages.mjs
The script produces:
| Output file | Purpose |
|---|---|
src/compiler/diagnosticInformationMap.generated.ts | TypeScript constants for every message, forming the Diagnostics namespace |
diagnosticMessages.generated.json | Intermediate JSON keyed by sanitized message identifiers; the input to LCL translation files |
The script derives a stable string key from each English message text by replacing non-alphanumeric characters and appending _N for each positional argument. For example:
| English message | Generated key |
|---|---|
Unterminated string literal. | Unterminated_string_literal_0 |
'{0}' expected. | _0_expected_0 |
Type '{0}' is not assignable to type '{1}'. | Type_0_is_not_assignable_to_type_1_0 |
These keys are used as ItemId values in LCL files and as the key field in DiagnosticMessage objects at runtime.
Sources: src/compiler/diagnosticMessages.json1-10 src/compiler/commandLineParser.ts54-56
DiagnosticMessage Type and Diagnostics NamespaceThe generated diagnosticInformationMap.generated.ts exposes a Diagnostics namespace consumed throughout the compiler.
The type of each entry is DiagnosticMessage, defined in src/compiler/types.ts:
DiagnosticMessage {
key: string // sanitized identifier, e.g. "Unterminated_string_literal_0"
category: DiagnosticCategory
code: number // stable numeric code, e.g. 1002
message: string // English message text (fallback if no locale loaded)
reportsUnnecessary?: {}
reportsDeprecated?: {}
isEarly?: boolean
}
DiagnosticCategory is a const enum:
Warning = 0
Error = 1
Suggestion = 2
Message = 3
Every component of the compiler references messages through the Diagnostics namespace:
Sources: src/compiler/types.ts1-50 src/compiler/checker.ts148-156 src/compiler/binder.ts49-52
LCL (Localization eXchange) is an XML format used by Microsoft's internal localization tooling (LocStudio). One LCL file exists per locale, stored under:
src/loc/lcl/<locale-code>/diagnosticMessages/diagnosticMessages.generated.json.lcl
Each file opens with an <LCX> root element declaring the source and target cultures:
Individual messages appear as <Item> elements. The ItemId attribute is the sanitized key (prefixed with ;). The <Val> under <Str> is the English source; the <Val> under <Tgt> is the translation:
| LCL attribute/element | Meaning |
|---|---|
ItemId | ; + sanitized message key |
SrcCul | Always en-US |
TgtCul | BCP-47 locale tag of target language |
<Val> under <Str> | English source string |
<Val> under <Tgt> | Translated string |
State="Translated" | Translation is complete |
State="New" | String not yet translated (falls back to English) |
Sources: src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl1-20 src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl1-10
Thirteen locale directories exist under src/loc/lcl/, corresponding to the 13 supported translation targets.
| Directory | BCP-47 code | Language |
|---|---|---|
chs | zh-CN | Chinese (Simplified) |
cht | zh-TW | Chinese (Traditional) |
csy | cs-CZ | Czech |
deu | de-DE | German |
esn | es-ES | Spanish (Spain) |
fra | fr-FR | French |
ita | it-IT | Italian |
jpn | ja-JP | Japanese |
kor | ko-KR | Korean |
plk | pl-PL | Polish |
ptb | pt-BR | Portuguese (Brazil) |
rus | ru-RU | Russian |
trk | tr-TR | Turkish |
Each locale directory contains a single file: diagnosticMessages/diagnosticMessages.generated.json.lcl.
Sources: src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5 src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5 src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5 src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5 src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5 src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl1-5
At runtime, the compiler selects either the English fallback or a localized string for every diagnostic message.
Two functions control which messages are active:
| Function | Location | Purpose |
|---|---|---|
setLocalizedDiagnosticMessages(messages) | src/compiler/ | Directly sets the active localized messages map (MapLike<string>) |
maybeSetLocalizedDiagnosticMessages(messages) | imported in src/services/services.ts | Conditionally sets the map; used during language service initialization |
Both accept a MapLike<string> where each key is a sanitized message key (the DiagnosticMessage.key field) and each value is the localized string.
When tsc --locale <locale> is used, the compiler loads the corresponding lib/<locale>/diagnosticMessages.generated.json file from the published package and calls setLocalizedDiagnosticMessages with its contents.
getLocaleSpecificMessage(message: DiagnosticMessage): string
This function checks the active localized messages map. If an entry exists for message.key, that localized string is returned; otherwise message.message (the English text) is returned as the fallback.
Sources: src/compiler/commandLineParser.ts54-56 src/services/services.ts228-229
Many messages contain {0}, {1}, etc. placeholder tokens that are replaced at the call site.
formatStringFromArgs(text: string, args: (string | number)[], baseIndex?: number): string
This function scans the message string and replaces each {N} token with args[N]. It is called internally by formatMessage and the createDiagnostic* family of functions.
formatMessage(dummy: any, message: DiagnosticMessage): string
This combines getLocaleSpecificMessage and formatStringFromArgs.
The diagnostic creation functions in the compiler chain these together:
| Function | Creates |
|---|---|
createCompilerDiagnostic(message, ...args) | A Diagnostic with no file location |
createFileDiagnostic(file, start, length, message, ...args) | A Diagnostic at a specific text span |
createDiagnosticForNode(node, message, ...args) | A Diagnostic for an AST node |
createDiagnosticForNodeFromMessageChain(node, chain) | A Diagnostic from a DiagnosticMessageChain |
Sources: src/compiler/utilities.ts97-100 src/compiler/checker.ts107-115 src/services/utilities.ts42-47
Sources: src/compiler/diagnosticMessages.json1-10 src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl1-10
Sources: src/compiler/checker.ts107-115 src/compiler/commandLineParser.ts54-56 src/services/services.ts228-229
DiagnosticMessage type to code entitiesSources: src/compiler/types.ts1-50 src/compiler/utilities.ts97-100 src/compiler/checker.ts73-116
To add a new diagnostic or change an existing one:
src/compiler/diagnosticMessages.json — add or modify the entry with the English text, category, and unique code.hereby generate-diagnostics (or the post-checkout hook will do it automatically). This regenerates diagnosticInformationMap.generated.ts and diagnosticMessages.generated.json.Diagnostics namespace in compiler source.State="New" in each LCL file until the localization team processes them; untranslated messages fall back to English at runtime.Changing the English text of an existing message changes its sanitized key, which breaks existing LCL translations for that entry — the old translations become orphaned and new ones must be provided.
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.