Agent Skillssanity-io/sanity › sanity-i18n-translate

sanity-i18n-translate

GitHub

指导正确使用Sanity框架中的i18n Translate组件,强调避免内联定义components以防止性能问题和状态丢失,并提供处理HTML标签、静态标记及需数据传递组件的最佳实践。

.agents/skills/sanity-i18n-translate/SKILL.md sanity-io/sanity

Trigger Scenarios

使用<Translate>组件渲染含标记的本地化字符串 添加或审查<Translate>用法 触发@repo/i18n/no-inline-translate-components lint规则

Install

npx skills add sanity-io/sanity --skill sanity-i18n-translate -g -y
More Options

Non-standard path

npx skills add https://github.com/sanity-io/sanity/tree/main/.agents/skills/sanity-i18n-translate -g -y

Use without installing

npx skills use sanity-io/sanity@sanity-i18n-translate

指定 Agent (Claude Code)

npx skills add sanity-io/sanity --skill sanity-i18n-translate -a claude-code -g -y

安装 repo 全部 skill

npx skills add sanity-io/sanity --all -g -y

预览 repo 内 skill

npx skills add sanity-io/sanity --list

SKILL.md

Frontmatter
{
    "name": "sanity-i18n-translate",
    "description": "Use the <Translate> i18n component correctly, especially its components map and componentProps. Use when rendering locale strings that contain markup or embedded components, when adding or reviewing <Translate> usages, or when the @repo\/i18n\/no-inline-translate-components lint rule fires."
}

Sanity i18n Translate

Start Here

<Translate> (from packages/sanity/src/core/i18n/Translate.tsx) renders locale resources that contain markup, eg 'Search for "<Red>{{keyword}}</Red>"'. The components prop maps tag names in the locale string to React components or intrinsic HTML tag names.

Prefer the plain t() function when the message has no markup — <Translate> is more expensive to render.

Law: never define components inline

Components in the components map MUST be stable, module-scope components. Never define them inline during render — each render then creates a new component identity, so React unmounts and remounts the subtree (losing state, DOM, and focus). This is the same class of bug as react/no-unstable-nested-components, and it is enforced for <Translate> by the in-repo oxlint rule @repo/i18n/no-inline-translate-components (implemented in the @repo/oxlint-plugin-i18n workspace package, wired via jsPlugins in .oxlintrc.json).

The rule only sees object literals written directly in the JSX attribute. Maps built during render some other way (useMemo, useCallback, factory calls) are just as wrong — hoist those too, even though the rule cannot flag them.

// ❌ Wrong - new component identity every render (and fails the lint rule)
;<Translate t={t} i18nKey="key" components={{Badge: ({children}) => <strong>{children}</strong>}} />

// ❌ Wrong - useMemo does not fix the identity problem across dependency changes
const components = useMemo(() => ({Badge: ({children}) => <b>{children}</b>}), [])

How to fix each shape

Plain HTML wrapper — map to the intrinsic tag name as a string. Strings never receive componentProps, so no stray DOM attributes:

<Translate t={t} i18nKey="key" components={{Code: 'code', Emphasis: 'em'}} />

Static markup (fixed link, styled wrapper) — hoist a module-scope component:

function DocsLink({children}: {children?: ReactNode}) {
  return <a href="https://www.sanity.io/docs">{children}</a>
}

;<Translate t={t} i18nKey="key" components={{DocsLink}} />

Component that needs data from render — hoist it and pass the data through componentProps. The object is forwarded to every non-string component in the map (including exotic ones like memo components), so declare only the props each component reads:

function VersionBadge({children, tone}: {children?: ReactNode; tone?: BadgeTone}) {
  return <VersionInlineBadge $tone={tone}>{children}</VersionInlineBadge>
}

;<Translate
  t={t}
  i18nKey="key"
  components={{VersionBadge}}
  componentProps={{tone: getReleaseTone(release)}}
/>

Gotchas

  • componentProps drives the generic: literal values widen ({tone: 'caution'} infers {tone: string}). Use as const on literals that must stay narrow: componentProps={{tone: 'caution' as const}}.
  • TComponentProps is constrained to object - primitives and null are compile errors.
  • Components receive children only for wrapping tags (<X>...</X>); self-closing tags (<X/>) render the component without children. Declare children optional.
  • Unmapped lowercase tags only render when listed in RECOGNIZED_HTML_TAGS in Translate.tsx; anything else falls back to interpolated plain text with a console warning.
  • Do not call component factories (eg getVersionInlineBadge) inside the hoisted component either - that recreates the render-time identity problem one level down, and the React Compiler lint flags it. Render the underlying component with a prop instead.

Reference implementations

  • packages/sanity/src/core/releases/tool/detail/ReleaseActivityListItem.tsx - componentProps passing an event object.
  • packages/@sanity/vision/src/components/VisionGuiResult.tsx - componentProps passing data to a self-closing component pair.
  • packages/sanity/src/core/studio/components/navbar/search/components/common/FilterLabel.tsx - several components sharing one componentProps object.
  • packages/sanity/src/core/i18n/__tests__/Translate.test.tsx - behavior coverage, including memo components and non-forwarding to intrinsic tags.

Version History

  • a94b3d8 Current 2026-08-28 22:14

Same Skill Collection

.agents/skills/code-review-and-quality/SKILL.md
.agents/skills/code-simplification/SKILL.md
.agents/skills/deslop/SKILL.md
.agents/skills/grill-me/SKILL.md
.agents/skills/improve-codebase-architecture/SKILL.md
.agents/skills/performance-optimization/SKILL.md
.agents/skills/playwright-cli/SKILL.md
.agents/skills/pr-description/SKILL.md
.agents/skills/rxjs-like-a-pro/SKILL.md
.agents/skills/sanity-config-reducers/SKILL.md
.agents/skills/sanity-default-plugins/SKILL.md
.agents/skills/sanity-plugin-authoring/SKILL.md
.agents/skills/sanity-visual-regression/SKILL.md
.agents/skills/stories/SKILL.md
.agents/skills/storybook-init/SKILL.md
.agents/skills/storybook-setup/SKILL.md
.agents/skills/storybook-upgrade/SKILL.md
.agents/skills/tdd/SKILL.md
.agents/skills/vercel-react-best-practices/SKILL.md
.agents/skills/write-a-skill/SKILL.md
.agents/skills/find-skills/SKILL.md
.agents/skills/playwright-best-practices/SKILL.md

Metadata

Files
0
Version
a94b3d8
Hash
85450869
Indexed
2026-08-28 22:14

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-29 01:57
浙ICP备14020137号-1 $Carte des visiteurs$