vtex-io-messages-and-i18n
Messages & Internationalization
When this skill applies
Use this skill when a VTEX IO app needs translated copy instead of hardcoded strings.
- Adding localized UI text to storefront or Admin apps
- Creating or updating
/messages/*.jsontranslation files - Defining message keys in
context.json - Reviewing React, Admin, or backend code that currently hardcodes user-facing copy
- Integrating app-specific translations with
vtex.messages
Do not use this skill for:
- general UI layout or component composition
- authorization, policies, or auth tokens
- service runtime sizing
- choosing between HTTP, GraphQL, and event-driven APIs
Decision rules
- Use the
messagesbuilder and translation files for user-facing copy instead of hardcoding labels, button text, or UI messages in source code. - Keep translation keys stable, explicit, and scoped to the app domain instead of generic keys such as
titleorbutton. The exact format may vary, but keys should remain specific, descriptive, and clearly owned by the app. - Prefix message IDs according to their UI surface or domain, for example
store/...for storefront messages andadmin/...for Admin or Site Editor messages, so keys stay organized and do not collide across contexts. - Define message keys in
/messages/context.jsonso VTEX IO can discover and manage the app’s translation surface. Keep it as a flat map ofmessageId -> descriptionand include the keys the app actually uses. - Keep translated message payloads small and app-focused. Do not turn the messages system into a general content store.
- In React or Admin UIs, prefer message IDs and localization helpers over literal copy in JSX.
- In backend or GraphQL flows, translate only when the app boundary truly needs localized text; otherwise return stable machine-oriented data and let the caller localize the presentation.
- Use app-level overrides of
vtex.messagesonly when the app truly needs to customize translation behavior or message resolution beyond normal app-local message files.
Hard constraints
Constraint: User-facing strings must come from the messages infrastructure
User-facing strings MUST come from the messages infrastructure instead of being hardcoded in components, handlers, or resolvers.
Why this matters
Hardcoded copy breaks localization, makes message review harder, and creates inconsistent behavior across storefront, Admin, and backend flows.
Detection
If you see labels, buttons, headings, alerts, or other user-facing text embedded directly in JSX or backend response formatting for a localized app, STOP and move that copy to message files.
Correct
<FormattedMessage id="admin/my-app.save" />
Wrong
<button>Save</button>
Constraint: Message keys must be declared and organized explicitly
Message keys MUST be app-scoped and represented in the app’s message configuration instead of being invented ad hoc in code.
Why this matters
Unstructured keys become hard to maintain, collide across app areas, and make message ownership unclear.
Detection
If code introduces new message IDs with no corresponding translation files or context.json entry, STOP and add the message contract explicitly.
Correct
{
"admin/my-app.save": "Save"
}
Wrong
{
"save": "Save"
}
Constraint: The messages system must not be used as a general content or configuration store
Translation files MUST contain localized copy, not operational configuration, secrets, or large content payloads.
Why this matters
The messages infrastructure is designed for translated strings. Using it for other data creates maintenance confusion and mixes localization concerns with configuration or content storage.
Detection
If message files contain API URLs, credentials, business rules, or long structured content blobs, STOP and move that data to app settings, configuration apps, or a content-specific mechanism.
Correct
{
"store/my-app.emptyState.title": "No records found"
}
Wrong
{
"apiBaseUrl": "https://partner.example.com",
"featureFlags": {
"betaMode": true
}
}
Preferred pattern
Recommended file layout:
.
├── messages/
│ ├── context.json
│ ├── en.json
│ └── pt.json
└── react/
└── components/
└── SaveButton.tsx
Minimal messages setup:
// messages/context.json
{
"admin/my-app.save": "Label for the save action in the admin settings page"
}
// messages/en.json
{
"admin/my-app.save": "Save",
"store/my-app.emptyState.title": "No records found"
}
// messages/pt.json
{
"admin/my-app.save": "Salvar"
}
import { FormattedMessage } from 'react-intl'
export function SaveButton() {
return <FormattedMessage id="admin/my-app.save" />
}
Backend or GraphQL translation pattern:
scalar IOMessage
type ProductLabel {
id: ID
label: IOMessage
}
type Query {
productLabel(id: ID!): ProductLabel
}
export const resolvers = {
Query: {
productLabel: async (_: unknown, { id }: { id: string }) => {
return {
id,
label: {
content: 'store/my-app.product-label',
description: 'Label for product badge',
from: 'en-US',
},
}
},
},
}
Keep a complete en.json as the default fallback, even when the app’s main audience uses another locale, so the messages system has a stable base for resolution and auto-translation behavior.
Use translated IDs in code, keep translation files explicit, and centralize user-facing copy in the messages system instead of scattering literals through the app.
Common failure modes
- Hardcoding user-facing strings in JSX, resolvers, or handler responses.
- Adding new message IDs in code without updating
context.jsonor the message files. - Using generic or collision-prone keys such as
title,save, orbutton. - Storing configuration values or non-localized business payloads in message files.
- Treating
vtex.messagesoverrides as the default path instead of app-local message management.
Review checklist
- Are user-facing strings sourced from the messages infrastructure instead of hardcoded in code?
- Are message keys explicit, app-scoped, and declared consistently?
- Does
context.jsonreflect the translation surface used by the app? - Are message files limited to localized copy rather than configuration or operational data?
- Is any customization of
vtex.messagestruly necessary for this app?
Related skills
vtex-io-storefront-react- Use when the main question is storefront component structure and shopper-facing UI behaviorvtex-io-admin-react- Use when the main question is Admin UI structure and operational interaction patternsvtex-io-graphql-api- Use when the main question is GraphQL schema and resolver design rather than translation infrastructure
Reference
- Messages - VTEX messages app and runtime translation behavior
- Overwriting the Messages app - How app-specific overrides of
vtex.messageswork