i18n Messaging
Manage and maintain i18n messaging for Daedalus multi-language support
Handles message extraction, validation, localization workflows, and schema compliance for Daedalus's internationalization system. Supports English (en-US) and Japanese (ja-JP) locales using react-intl and Format.js.
Message Schema
Messages in Daedalus follow a structured format using defineMessages() from react-intl:
{
messageKey: {
id: "namespace.context.messageKey", // Unique identifier with dot notation
defaultMessage: "!!!Message text with placeholders",
description: "Context/description for translators",
values?: Record<string, any> // Runtime variable placeholders
}
}
ID Naming Convention
- Format:
namespace.context.messageKey(dot-separated) - Prefix: All messages start with
!!!in defaultMessage - Examples:
global.errors.fieldIsRequiredapi.errors.IncorrectPasswordErrorglobal.ada.name
Variable Placeholders
Messages with dynamic content use curly braces:
knownMnemonicWordCount: {
id: 'global.info.knownMnemonicWordCount',
defaultMessage: '!!!{actual} of {required} words entered',
values: { actual: 5, required: 12 }
}
Operations
1. Extract Messages
Extract all i18n messages from source code to generate message catalog.
yarn i18n:extract
What it does:
- Scans
source/**/*.{ts,tsx}files - Extracts
defineMessages()and<FormattedMessage />calls - Ignores
.d.tsTypeScript declaration files - Outputs to
translations/messages.json - Records source file locations
When to use:
- After adding new messages with
defineMessages() - Before running
i18n:check - As part of
i18n:manageworkflow
Output format:
[
{
"path": "source/main/ipc/handlers.ts",
"descriptors": [
{
"id": "global.errors.fieldIsRequired",
"defaultMessage": "!!!This field is required.",
"description": "Error message when required fields are left empty."
}
]
}
]
2. Check Translations
Validate translation files for consistency and completeness against extracted messages.
yarn i18n:check
What it does:
- Compares extracted messages with translation files
- Validates en-US and ja-JP locales
- Ensures all message IDs are present
- Detects missing or obsolete translations
- Uses
react-intl-translations-managerto manage lifecycle
When to use:
- After extracting new messages
- Before committing translation changes
- To validate message format across locales
Validates:
- All en-US messages have corresponding ja-JP translations
- No orphaned message IDs
- Message structure consistency (id, defaultMessage, description)
3. Manage Translations
Combined operation: extract messages AND validate translations in one command.
yarn i18n:manage
Equivalent to: yarn i18n:extract && yarn i18n:check
When to use:
- Primary workflow for updating i18n content
- Part of
check:allverification - Before creating commits with messaging changes
Supported Locales
| Locale | Language | Directory |
|---|---|---|
| en-US | English | source/renderer/app/i18n/locales/en-US.json |
| ja-JP | Japanese | source/renderer/app/i18n/locales/ja-JP.json |
Locale Files Structure
source/renderer/app/i18n/locales/
├── defaultMessages.json # All extracted messages (auto-generated)
├── en-US.json # English translations (English only)
├── ja-JP.json # Japanese translations
├── whitelist_en-US.json # Approved en-US messages
├── whitelist_ja-JP.json # Approved ja-JP messages
└── terms-of-use/ # Locale-specific documents
Best Practices
Adding New Messages
- Use
defineMessages()or<FormattedMessage />in source code - Follow naming convention:
namespace.context.messageKey - Include descriptive
descriptionfor translators - Always prefix defaultMessage with
!!! - Run
yarn i18n:extractto register new messages
Validating Message IDs
Do:
- Use hierarchical namespaces:
wallet.send.confirmButton - Keep IDs consistent across related messages
- Document placeholder variables in description
- Use lowercase with dots as separators
Don't:
- Use spaces or special characters in IDs
- Duplicate IDs across features
- Leave placeholders undocumented
- Change ID format mid-project
Working with Placeholders
Messages with runtime values use curly braces:
// Define message with placeholder
notEnoughFunds: {
id: 'wallet.errors.notEnoughFunds',
defaultMessage: '!!!Remaining balance: {balance} ADA',
description: 'Error when insufficient funds'
}
// Use at runtime
<FormattedMessage
id="wallet.errors.notEnoughFunds"
defaultMessage="Remaining balance: {balance} ADA"
values={{ balance: walletBalance }}
/>
Translation Flow
- Extract: Run
yarn i18n:extractafter code changes - Check: Run
yarn i18n:checkto validate - Review: Update localized JSON files as needed
- Verify: Run
check:allbefore committing - Commit: Include updated
translations/messages.jsonand locale files
Generated !!! Placeholders
yarn i18n:manageseeds missing locale entries fromdefaultMessage, so new keys inen-US.jsonandja-JP.jsoncan be written with the!!!prefix.- Treat
!!!in locale files as a new or untranslated message marker, not polished release copy. - This workflow does not remove the prefix automatically. If locale polish is in scope, manually replace new
en-US.jsonentries with approved English copy and add real Japanese translations inja-JP.jsonbefore commit. - If the task only covers extraction or catalog sync, keeping generated
!!!placeholders is acceptable, but document the follow-up translation work explicitly.
Related Files
| File | Purpose |
|---|---|
translations/translation-runner.ts |
Validates translations (manages mapping) |
translations/formatter.js |
Custom extraction format for Format.js |
translations/messages.json |
Extracted message catalog |
source/renderer/app/i18n/global-messages.ts |
Global message definitions |
source/renderer/app/i18n/errors.ts |
Error message definitions |
source/renderer/app/i18n/types.ts |
TypeScript types for messages |
Troubleshooting
Messages not extracted
- Verify
defineMessages()is imported fromreact-intl - Check files are in
source/**/*.{ts,tsx}(not .d.ts) - Run
yarn clear:translationsthenyarn i18n:extract
Translation validation fails
- Ensure all en-US messages have ja-JP equivalents
- Check message IDs match exactly (case-sensitive)
- Verify JSON format is valid in locale files
Missing or duplicate IDs
- Check for conflicting message keys across files
- Remove obsolete messages from translation files manually
- Re-run
yarn i18n:manageto refresh state
Template: Adding New Message
import { defineMessages } from 'react-intl';
// In your component file or messages.ts
export const componentMessages = defineMessages({
newMessageKey: {
id: 'feature.component.newMessageKey',
defaultMessage: '!!!Default English text',
description: 'Context for translators explaining where/how this message is used',
},
messageWithPlaceholder: {
id: 'feature.component.messageWithPlaceholder',
defaultMessage: '!!!You have {count} items',
description: 'Message showing item count with placeholder',
},
});
Then run: yarn i18n:manage