Message descriptor types and processing patterns supported by babel-plugin-formatjs for React Intl message extraction and transformation.
Core interfaces for representing message descriptors and extraction results (available as TypeScript types).
/**
* Basic message descriptor interface - represents a single translatable message
*/
interface MessageDescriptor {
/** Unique identifier for the message */
id: string;
/** Default message text with ICU MessageFormat syntax support */
defaultMessage?: string;
/** Human-readable description for translators (removed during processing) */
description?: string;
}
/**
* Extended message descriptor with source location information
*/
interface ExtractedMessageDescriptor extends MessageDescriptor {
/** Source file path where message was found */
file?: string;
/** Start position in source file */
start?: number;
/** End position in source file */
end?: number;
/** Line number in source file */
line?: number;
/** Column number in source file */
column?: number;
}
/**
* Result of message extraction process (exported from main module)
*/
interface ExtractionResult<M = Record<string, string>> {
/** Array of extracted message descriptors */
messages: ExtractedMessageDescriptor[];
/** Additional metadata extracted from pragma comments */
meta: M;
}The plugin recognizes and processes these React Intl patterns during Babel transformation:
Extracts multiple message descriptors from object properties.
import { defineMessages } from 'react-intl';
const messages = defineMessages({
greeting: {
id: 'app.greeting',
defaultMessage: 'Hello {name}!',
description: 'Greeting with name placeholder'
},
farewell: {
// ID will be auto-generated if not provided
defaultMessage: 'Goodbye!',
description: 'Simple farewell message'
}
});
// After processing (descriptions removed, IDs generated):
const messages = defineMessages({
greeting: {
id: 'app.greeting',
defaultMessage: 'Hello {name}!'
},
farewell: {
id: '[generated-hash]', // Auto-generated based on content
defaultMessage: 'Goodbye!'
}
});Extracts a single message descriptor from object expression.
import { defineMessage } from 'react-intl';
const message = defineMessage({
id: 'app.single',
defaultMessage: 'Single message',
description: 'Example single message'
});
// After processing:
const message = defineMessage({
id: 'app.single',
defaultMessage: 'Single message'
});Extracts messages from intl.formatMessage() and similar function calls.
// Direct call
intl.formatMessage({
id: 'app.dynamic',
defaultMessage: 'Dynamic message',
description: 'Runtime message'
});
// Function name variants (configurable)
formatMessage({
defaultMessage: 'Function call message'
});
$t({
defaultMessage: 'Short-hand function'
});
$formatMessage({
defaultMessage: 'Vue-style function'
});Extracts messages from JSX component attributes.
<FormattedMessage
id="app.jsx"
defaultMessage="JSX message with {placeholder}"
description="Message in JSX component"
values={{ placeholder: 'value' }}
/>
// After processing (description removed):
<FormattedMessage
id="app.jsx"
defaultMessage="JSX message with {placeholder}"
values={{ placeholder: 'value' }}
/>Process additional component names when configured with additionalComponentNames.
// When additionalComponentNames: ['CustomMessage', 'TransText']
<CustomMessage
id="app.custom"
defaultMessage="Custom component message"
description="From custom component"
/>
<TransText
defaultMessage="Another custom component"
/>Process additional function names when configured with additionalFunctionNames.
// When additionalFunctionNames: ['translate', '__', 'i18n']
translate({
id: 'app.translate',
defaultMessage: 'Translate function message'
});
__({
defaultMessage: 'Underscore function message'
});
i18n({
defaultMessage: 'I18n function message'
});The plugin validates and processes ICU MessageFormat syntax in message strings.
defineMessage({
defaultMessage: 'Hello {name}!'
});
defineMessage({
defaultMessage: 'You have {count} items'
});defineMessage({
defaultMessage: 'You have {count, plural, one {# item} other {# items}}'
});
defineMessage({
defaultMessage: '{itemCount, plural, =0 {no items} =1 {one item} other {# items}}'
});defineMessage({
defaultMessage: '{gender, select, male {He} female {She} other {They}} will respond'
});defineMessage({
defaultMessage: 'Today is {today, date, full}'
});
defineMessage({
defaultMessage: 'Price: {price, number, currency}'
});The plugin performs these transformations during processing:
When no id is provided, the plugin generates one based on configuration:
// Input
defineMessage({
defaultMessage: 'Hello world!'
});
// Output (with default pattern [sha512:contenthash:base64:6])
defineMessage({
id: 'a1b2c3',
defaultMessage: 'Hello world!'
});Descriptions are always removed from the transformed code to reduce bundle size:
// Input
defineMessage({
id: 'app.greeting',
defaultMessage: 'Hello!',
description: 'Greeting message'
});
// Output
defineMessage({
id: 'app.greeting',
defaultMessage: 'Hello!'
});When removeDefaultMessage: true, default messages are removed in production:
// Input
defineMessage({
id: 'app.greeting',
defaultMessage: 'Hello!'
});
// Output (removeDefaultMessage: true)
defineMessage({
id: 'app.greeting'
});When ast: true, messages are pre-parsed for runtime efficiency:
// Input
defineMessage({
id: 'app.greeting',
defaultMessage: 'Hello {name}!'
});
// Output (ast: true)
defineMessage({
id: 'app.greeting',
defaultMessage: [
{ type: 'literal', value: 'Hello ' },
{ type: 'argument', value: 'name' },
{ type: 'literal', value: '!' }
]
});The plugin throws compilation errors for:
// This will cause a build error
defineMessage({
defaultMessage: 'Hello {name!' // Missing closing brace
});// This will cause a build error
const dynamicId = 'computed-id';
defineMessage({
id: dynamicId, // Must be statically evaluable
defaultMessage: 'Dynamic message'
});// This will cause a build error
defineMessage({
description: 'Only description provided' // Need id or defaultMessage
});Configure callbacks to receive extracted messages and metadata:
// babel.config.js
{
plugins: [
["babel-plugin-formatjs", {
onMsgExtracted: (filename, messages) => {
// Process extracted messages
console.log(`Found ${messages.length} messages in ${filename}`);
messages.forEach(msg => {
console.log(` ${msg.id}: ${msg.defaultMessage}`);
});
},
onMetaExtracted: (filename, meta) => {
// Process extracted metadata from pragma comments
console.log(`Meta from ${filename}:`, meta);
}
}]
]
}Extract metadata from pragma comments in source files:
// @react-intl namespace:user-profile locale:en-US region:america
import { defineMessages } from 'react-intl';
const messages = defineMessages({
greeting: {
defaultMessage: 'Hello!'
}
});
// Extracted metadata: { namespace: 'user-profile', locale: 'en-US', region: 'america' }