Core utilities for parsing, processing, and manipulating localize messages, including metadata extraction, message ID computation, and message structure handling.
Parses a $localize tagged string into a structured format for translation or extraction.
/**
* Parse a $localize tagged string into structure for translation/extraction.
* Extracts metadata, placeholders, and substitutions from template literal.
*
* @param messageParts - Template string array parts
* @param expressions - Expression values (optional)
* @param location - Source location info (optional)
* @param messagePartLocations - Location info for each part (optional)
* @param expressionLocations - Location info for expressions (optional)
* @returns Parsed message structure with metadata and placeholders
*/
function parseMessage(
messageParts: TemplateStringsArray,
expressions?: readonly any[],
location?: SourceLocation,
messagePartLocations?: (SourceLocation | undefined)[],
expressionLocations?: (SourceLocation | undefined)[]
): ParsedMessage;
interface ParsedMessage extends MessageMetadata {
id: MessageId;
substitutions: Record<string, any>;
messageParts: string[];
placeholderNames: string[];
associatedMessageIds?: Record<string, MessageId>;
substitutionLocations?: Record<string, SourceLocation | undefined>;
messagePartLocations?: (SourceLocation | undefined)[];
location?: SourceLocation;
}Usage Example:
import { parseMessage } from "@angular/localize";
// Parse a template literal
const messageParts = ["Hello, ", "!"] as TemplateStringsArray;
messageParts.raw = ["Hello, ", "!"];
const expressions = ["Alice"];
const parsed = parseMessage(messageParts, expressions);
console.log(parsed);
// {
// id: "2788806693285683417",
// text: "Hello, {$PH}!",
// substitutions: { PH: "Alice" },
// messageParts: ["Hello, ", "!"],
// placeholderNames: ["PH"],
// meaning: "",
// description: "",
// ...
// }Parses metadata block from the first part of a $localize tagged string.
/**
* Parse metadata from message part (cooked + raw).
* Extracts meaning, description, customId and legacyIds from metadata block.
* Metadata is serialized delimited by |, @@, and ␟ respectively.
*
* @param cooked - Cooked version of message part
* @param raw - Raw version of message part
* @returns Object containing parsed metadata
*/
function parseMetadata(cooked: string, raw: string): MessageMetadata;
interface MessageMetadata {
text: string;
meaning?: string;
description?: string;
customId?: string;
legacyIds?: string[];
location?: SourceLocation;
}Usage Examples:
import { parseMetadata } from "@angular/localize";
// Parse full metadata block
const metadata1 = parseMetadata(
":page-title|The main page title@@homepage-title:Welcome",
":page-title|The main page title@@homepage-title:Welcome"
);
console.log(metadata1);
// {
// text: "Welcome",
// meaning: "page-title",
// description: "The main page title",
// customId: "homepage-title"
// }
// Parse with legacy IDs
const metadata2 = parseMetadata(
":@@new-id␟legacy-1␟legacy-2:Message",
":@@new-id␟legacy-1␟legacy-2:Message"
);
console.log(metadata2);
// {
// text: "Message",
// customId: "new-id",
// legacyIds: ["legacy-1", "legacy-2"]
// }
// No metadata block
const metadata3 = parseMetadata("Simple message", "Simple message");
console.log(metadata3);
// { text: "Simple message" }Parses placeholder metadata from message parts following substitutions.
/**
* Parse placeholder metadata from message part (cooked + raw).
* Extracts placeholderName and associatedMessageId from block.
* Metadata is serialized delimited by @@.
*
* @param cooked - Cooked version of message part
* @param raw - Raw version of message part
* @returns Object with placeholder metadata and remaining text
*/
function parsePlaceholder(
cooked: string,
raw: string
): {
messagePart: string;
placeholderName?: string;
associatedMessageId?: string;
};Usage Examples:
import { parsePlaceholder } from "@angular/localize";
// Named placeholder
const result1 = parsePlaceholder(":itemCount: items", ":itemCount: items");
console.log(result1);
// {
// messagePart: " items",
// placeholderName: "itemCount"
// }
// Placeholder with associated message ID
const result2 = parsePlaceholder(
":userName@@user-id: profile",
":userName@@user-id: profile"
);
console.log(result2);
// {
// messagePart: " profile",
// placeholderName: "userName",
// associatedMessageId: "user-id"
// }
// No placeholder metadata
const result3 = parsePlaceholder(" remaining", " remaining");
console.log(result3);
// { messagePart: " remaining" }Computes a unique message ID hash from message string and meaning.
/**
* Compute unique message ID from message string and meaning.
* Uses same algorithm as Angular compiler for consistency.
*
* @param messageString - The message text with placeholder syntax
* @param meaning - Optional meaning to distinguish identical messages
* @returns Computed message ID string
*/
function computeMsgId(messageString: string, meaning: string): string;Usage Examples:
import { computeMsgId } from "@angular/localize";
// Simple message
const id1 = computeMsgId("Hello, World!", "");
console.log(id1); // "4286451273117902052"
// Message with placeholder
const id2 = computeMsgId("Hello, {$PH}!", "");
console.log(id2); // "2788806693285683417"
// Same message, different meaning
const id3 = computeMsgId("Home", "navigation");
const id4 = computeMsgId("Home", "location");
console.log(id3 !== id4); // true - different IDsSplits a message part into an optional metadata block and remaining text.
/**
* Split message part into optional delimited block and remaining text.
* Blocks are delimited by colon characters at start and end.
* Handles escaped colons (\:) that should not be treated as delimiters.
*
* @param cooked - Cooked version of message part
* @param raw - Raw version of message part
* @returns Object with block text (if exists) and remaining text
* @throws Error if block is unterminated
*/
function splitBlock(cooked: string, raw: string): {
text: string;
block?: string;
};Usage Examples:
import { splitBlock } from "@angular/localize";
// With metadata block
const result1 = splitBlock(":meaning|desc@@id:Message text", ":meaning|desc@@id:Message text");
console.log(result1);
// {
// block: "meaning|desc@@id",
// text: "Message text"
// }
// No metadata block
const result2 = splitBlock("Simple message", "Simple message");
console.log(result2);
// { text: "Simple message" }
// Escaped colon (not a block)
const result3 = splitBlock("\\:Not a block", "\\:Not a block");
console.log(result3);
// { text: ":Not a block" }Finds the end of a metadata block by locating the first non-escaped colon.
/**
* Find end of marked block indicated by first non-escaped colon.
* Handles escaped colons in raw string that shouldn't terminate block.
*
* @param cooked - Cooked string with escape sequences processed
* @param raw - Raw string with escape sequences in place
* @returns Index of end of block marker
* @throws Error if block is unterminated
*/
function findEndOfBlock(cooked: string, raw: string): number;Usage Example:
import { findEndOfBlock } from "@angular/localize";
// Find end of metadata block
const endIndex = findEndOfBlock(
":meaning|description@@id:message",
":meaning|description@@id:message"
);
console.log(endIndex); // 22 (index of second colon)
// With escaped colon inside block
const endIndex2 = findEndOfBlock(
":desc with \\: colon:message",
":desc with \\: colon:message"
);
console.log(endIndex2); // 19 (index after escaped colon)Creates a ParsedTranslation from message parts and placeholder names.
/**
* Create ParsedTranslation from messageParts and placeholderNames.
* Used internally for converting translation strings to usable format.
*
* @param messageParts - Message parts to appear in ParsedTranslation
* @param placeholderNames - Names of placeholders between parts
* @returns ParsedTranslation structure
*/
function makeParsedTranslation(
messageParts: string[],
placeholderNames: string[]
): ParsedTranslation;
interface ParsedTranslation extends MessageMetadata {
messageParts: TemplateStringsArray;
placeholderNames: string[];
}Parses a target message string into a ParsedTranslation structure.
/**
* Parse messageParts and placeholderNames from target message.
* Used by loadTranslations() to convert strings to translation format.
*
* @param messageString - Target message with {$placeholder} syntax
* @returns ParsedTranslation structure ready for use
*/
function parseTranslation(messageString: TargetMessage): ParsedTranslation;
type TargetMessage = string;Usage Example:
import { parseTranslation } from "@angular/localize";
const translation = parseTranslation("¡Hola, {$PH}!");
console.log(translation);
// {
// text: "¡Hola, {$PH}!",
// messageParts: ["¡Hola, ", "!"],
// placeholderNames: ["PH"]
// }Creates the specialized TemplateStringsArray passed to tagged template functions.
/**
* Create specialized array passed to tagged-string tag functions.
* Adds raw property containing unprocessed string parts.
*
* @param cooked - Message parts with escape codes processed
* @param raw - Message parts with escaped codes as-is
* @returns TemplateStringsArray for tagged template usage
*/
function makeTemplateObject(cooked: string[], raw: string[]): TemplateStringsArray;Error thrown when a translation is not found for a message.
class MissingTranslationError extends Error {
private readonly type = 'MissingTranslationError';
constructor(readonly parsedMessage: ParsedMessage);
}
/**
* Type guard to check if error is MissingTranslationError.
*
* @param e - Error to check
* @returns True if error is MissingTranslationError
*/
function isMissingTranslationError(e: any): e is MissingTranslationError;Usage Example:
import { isMissingTranslationError } from "@angular/localize";
try {
// Some translation operation
translateMessage(messageParts, substitutions);
} catch (error) {
if (isMissingTranslationError(error)) {
console.log(`Missing translation for: ${error.parsedMessage.id}`);
console.log(`Message text: ${error.parsedMessage.text}`);
} else {
throw error;
}
}/** Character marking start and end of metadata blocks */
const BLOCK_MARKER = ':';
/** Separator between meaning and description in metadata */
const MEANING_SEPARATOR = '|';
/** Separator between description and custom ID in metadata */
const ID_SEPARATOR = '@@';
/** Marker separating legacy IDs from other metadata */
const LEGACY_ID_INDICATOR = '\u241F';