.agents/skills/i18n-standards/SKILL.md
Centralized guidelines on how to structure and consume i18n features using react-intl.
npx skillsauth add filippovskii09/quize-audit React Internationalization (i18n) StandardsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This application uses the react-intl library to support multiple languages (English and Ukrainian) and maintain a globally scalable codebase without hardcoded strings.
Based on industry standards (like Open edX and Atlassian implementations), using react-intl requires several strict paradigms to ensure typesafety, context for translators, and correct extraction pipelines.
{count, plural, ...}) instead of logical branching in JS (count > 1 ? 'items' : 'item').messages.ts)Any component requiring text must define a messages.ts file parallel to its index.tsx.
YouMUST wrap definitions using defineMessages from react-intl.
messages.tsauditTool.components.AdminDashboard.title.defaultMessage.description metadata to give context to translators.Example:
// src/components/admin/AdminDashboard/messages.ts
import { defineMessages } from 'react-intl';
export default defineMessages({
dashboardTitle: {
id: 'app.admin.AdminDashboard.dashboardTitle',
defaultMessage: 'Admin Dashboard',
description: 'Main heading title for the Admin Dashboard page',
},
reviewSubtitle: {
id: 'app.admin.AdminDashboard.reviewSubtitle',
defaultMessage: 'Review exported audit results.',
description: 'Subtitle for the Admin Dashboard explaining its purpose',
},
});
<FormattedMessage> component (Preferred)For regular rendering inside DOM elements, use the FormattedMessage component. Pass the extracted object from messages.ts.
import { FormattedMessage } from 'react-intl';
import messages from './messages';
export const AdminDashboard = () => (
<h2><FormattedMessage {...messages.dashboardTitle} /></h2>
);
useIntl Hook (For strings only)When you must pass raw strings (e.g., placeholder, aria-label, title), use the useIntl hook.
import { useIntl } from 'react-intl';
import messages from './messages';
export const InputForm = () => {
const intl = useIntl();
return (
<input
type="text"
placeholder={intl.formatMessage(messages.searchPlaceholder)}
/>
);
};
Always use translation variables (values prop) over string concatenation.
Example with Variables:
// messages.ts
greeting: {
id: 'app.user.greeting',
defaultMessage: 'Welcome back, {userName}!',
}
// Component
<FormattedMessage {...messages.greeting} values={{ userName: user.name }} />
Example with Plurals:
// messages.ts
itemCount: {
id: 'app.cart.itemCount',
defaultMessage: 'You have {count, plural, =0 {no items} one {1 item} other {# items}} in your cart.'
}
The entire React tree must be wrapped in <IntlProvider locale={locale} messages={messages}>.
Language packs (JSON files mapped by ID) are stored centrally at the top level or lazy-loaded depending on size.
development
Domain skill for React internationalization setup with react-intl, locale switching, and typed i18n context. Use when adding new translations or extending locale behavior.
development
Domain skill for reusable typed React hooks used in business logic. Use when extending or validating shared hooks like local storage and pagination.
development
Reusable Prettier formatting recipe for TypeScript and frontend repositories. Use when enforcing consistent code style and integrating format checks in hooks.
tools
Declarative pre-commit framework recipe for polyglot repositories with stage-aware hooks (pre-commit and pre-push). Use when repositories need non-Node quality gates or mixed toolchains.