mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-15 04:31:27 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95d58fc2dd | |||
| cd52c3b7f2 | |||
| 4e4ccebacb | |||
| 85b4114248 | |||
| b54a4fc2d0 |
@@ -1,4 +1,4 @@
|
||||
**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
|
||||
# ECC
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md)
|
||||
| [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
| [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md)
|
||||
[**English**](README.md) | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
# Glossar / Glossary
|
||||
|
||||
Einheitliches Terminologie-Glossar für die deutsche (de-DE) Übersetzung von ECC.
|
||||
|
||||
Leitlinie: Etablierte englische Fachbegriffe und ECC-Oberflächennamen (`agents/`, `skills/`,
|
||||
`commands/`, `hooks/`, `rules/`) bleiben **englisch** — sie sind im deutschsprachigen
|
||||
Entwickleralltag Standard und entsprechen Verzeichnis-/Befehlsnamen im Repo. Begriffe mit
|
||||
einer klaren, gebräuchlichen deutschen Entsprechung werden **übersetzt**.
|
||||
|
||||
| English | Deutsch | Notiz |
|
||||
|---------|---------|-------|
|
||||
| Agent | Agent | bleibt englisch — ECC-Oberfläche (`agents/`) |
|
||||
| Skill | Skill | bleibt englisch — ECC-Oberfläche (`skills/`) |
|
||||
| Hook | Hook | bleibt englisch — ECC-Oberfläche (`hooks/`) |
|
||||
| Command | Command | bleibt englisch als ECC-Oberfläche (`commands/`); generisch sonst „Befehl“ |
|
||||
| Rule | Rule | bleibt englisch als ECC-Oberfläche (`rules/`); generisch sonst „Regel“ |
|
||||
| Harness | Harness | bleibt englisch — keine etablierte deutsche Entsprechung |
|
||||
| Instinct | Instinct | bleibt englisch — ECC-Begriff aus Continuous Learning |
|
||||
| Plugin | Plugin | bleibt englisch |
|
||||
| Marketplace | Marketplace | bleibt englisch — Anthropic-Produktbegriff |
|
||||
| Worktree | Worktree | bleibt englisch — Git-Fachbegriff |
|
||||
| Subagent | Subagent | bleibt englisch |
|
||||
| Frontmatter | Frontmatter | bleibt englisch; YAML-Feldnamen bleiben englisch |
|
||||
| Continuous Learning | Continuous Learning | ECC-Feature-Name bleibt englisch; beschreibend „kontinuierliches Lernen“ |
|
||||
| Memory | Memory | als ECC-Konzept englisch; generisch „Speicher“ |
|
||||
| Context window | Kontextfenster | |
|
||||
| Token | Token | |
|
||||
| Coverage | Coverage | „Testabdeckung“, wo beschreibend |
|
||||
| Test-Driven Development | testgetriebene Entwicklung | Kürzel TDD beibehalten |
|
||||
| Code review | Code-Review | |
|
||||
| Refactoring | Refactoring | |
|
||||
| Pull request | Pull Request | |
|
||||
| Commit | Commit | |
|
||||
| Branch | Branch | |
|
||||
| Merge | Merge / zusammenführen | je nach Kontext |
|
||||
| Build | Build | |
|
||||
| Deploy | Deployment / deployen | |
|
||||
| Pipeline | Pipeline | |
|
||||
| Orchestration | Orchestrierung | |
|
||||
| Repository | Repository | kurz „Repo“ zulässig |
|
||||
| Dependency | Abhängigkeit | |
|
||||
| Edge case | Grenzfall | |
|
||||
| Best practice | Best Practice | |
|
||||
| Anti-pattern | Anti-Pattern | |
|
||||
| Middleware | Middleware | |
|
||||
| Endpoint | Endpoint | |
|
||||
| Schema | Schema | |
|
||||
| Payload | Payload | |
|
||||
| Callback | Callback | |
|
||||
| Checkpoint | Checkpoint | |
|
||||
| Linter | Linter | |
|
||||
| Formatter | Formatter | |
|
||||
| Staging | Staging | |
|
||||
| Production | Produktion / Produktivumgebung | je nach Kontext |
|
||||
| Debugging | Debugging | |
|
||||
| Logging | Logging | |
|
||||
| Monitoring | Monitoring | |
|
||||
| Rate limit | Rate-Limit | |
|
||||
| Retry | Retry / Wiederholung | |
|
||||
| Fallback | Fallback | |
|
||||
| Graceful degradation | Graceful Degradation | |
|
||||
| Sandboxing | Sandboxing | |
|
||||
| Sanitization | Sanitisierung | |
|
||||
| Selective install | selektive Installation | |
|
||||
| Profile | Profil | Installationsprofil |
|
||||
| Component | Komponente | Installationskomponente |
|
||||
| Module | Modul | Installationsmodul |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
**言語:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
**言語:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
**言語 / Language / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**언어:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | 한국어 | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
**언어:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | 한국어 | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / 언어 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Idioma:** [English](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | Português (Brasil) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
**Idioma:** [English](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | Português (Brasil) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
**Idioma / Language / 语言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Português (Brasil)](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Português (Brasil)](README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
**Язык:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
**Язык:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
**Язык / 语言 / 語言 / Dil / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | **Русский** | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
**ภาษา:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย** | [Deutsch](../de-DE/README.md)
|
||||
**ภาษา:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย**
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
**ภาษา / Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย** | [Deutsch](../de-DE/README.md)
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | **ไทย**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
**Dil / Language / 语言 / 語言 / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [**Türkçe**](README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [**Türkçe**](README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Ngôn ngữ:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
**Ngôn ngữ:** [English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md)
|
||||
|
||||
# Everything Claude Code
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
**Ngôn ngữ / Language / 语言 / 語言 / Dil / Язык**
|
||||
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[English](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | [繁體中文](../zh-TW/README.md) | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | **Tiếng Việt** | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
**Language / 语言 / 語言 / Dil / Язык / Ngôn ngữ**
|
||||
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | **繁體中文** | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md) | [Deutsch](../de-DE/README.md)
|
||||
[**English**](../../README.md) | [Português (Brasil)](../pt-BR/README.md) | [简体中文](../../README.zh-CN.md) | **繁體中文** | [日本語](../ja-JP/README.md) | [한국어](../ko-KR/README.md) | [Türkçe](../tr/README.md) | [Русский](../ru/README.md) | [Tiếng Việt](../vi-VN/README.md) | [ไทย](../th/README.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -589,14 +589,6 @@
|
||||
"modules": [
|
||||
"docs-zh-tw"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "locale:de-de",
|
||||
"family": "locale",
|
||||
"description": "German (de-DE) translated reference docs installed to ~/.claude/docs/de-DE/.",
|
||||
"modules": [
|
||||
"docs-de-de"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -843,22 +843,6 @@
|
||||
"defaultInstall": false,
|
||||
"cost": "heavy",
|
||||
"stability": "stable"
|
||||
},
|
||||
{
|
||||
"id": "docs-de-de",
|
||||
"kind": "docs",
|
||||
"description": "German (de-DE) translated reference docs for agents, commands, skills, and rules.",
|
||||
"paths": [
|
||||
"docs/de-DE"
|
||||
],
|
||||
"targets": [
|
||||
"claude",
|
||||
"claude-project"
|
||||
],
|
||||
"dependencies": [],
|
||||
"defaultInstall": false,
|
||||
"cost": "heavy",
|
||||
"stability": "stable"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
"agent.yaml",
|
||||
"agents/",
|
||||
"commands/",
|
||||
"docs/de-DE/",
|
||||
"docs/ja-JP/",
|
||||
"docs/ko-KR/",
|
||||
"docs/pt-BR/",
|
||||
|
||||
@@ -14,7 +14,7 @@ const COMPONENT_FAMILY_PREFIXES = {
|
||||
skill: 'skill:',
|
||||
locale: 'locale:',
|
||||
};
|
||||
const SUPPORTED_LOCALES = Object.freeze(['ja', 'zh-CN', 'ko-KR', 'pt-BR', 'ru', 'tr', 'vi-VN', 'zh-TW', 'de-DE']);
|
||||
const SUPPORTED_LOCALES = Object.freeze(['ja', 'zh-CN', 'ko-KR', 'pt-BR', 'ru', 'tr', 'vi-VN', 'zh-TW']);
|
||||
const LOCALE_ALIAS_TO_COMPONENT_ID = Object.freeze({
|
||||
'ja': 'locale:ja',
|
||||
'ja-JP': 'locale:ja',
|
||||
@@ -29,8 +29,6 @@ const LOCALE_ALIAS_TO_COMPONENT_ID = Object.freeze({
|
||||
'vi-VN': 'locale:vi-vn',
|
||||
'vi': 'locale:vi-vn',
|
||||
'zh-TW': 'locale:zh-tw',
|
||||
'de-DE': 'locale:de-de',
|
||||
'de': 'locale:de-de',
|
||||
});
|
||||
|
||||
function listSupportedLocales() {
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
---
|
||||
name: frontend-a11y
|
||||
description: >
|
||||
Accessibility patterns for React and Next.js — semantic HTML, ARIA attributes,
|
||||
form labeling, keyboard navigation, focus management, and screen reader support.
|
||||
Use when building any interactive UI component or form.
|
||||
origin: community
|
||||
---
|
||||
|
||||
# Frontend Accessibility Patterns
|
||||
|
||||
Practical accessibility patterns for React and Next.js. Covers the issues most commonly flagged in code review: missing form labels, incorrect ARIA usage, non-semantic interactive elements, and broken keyboard navigation.
|
||||
|
||||
## When to Activate
|
||||
|
||||
- Building or reviewing form components (`<input>`, `<select>`, `<textarea>`)
|
||||
- Creating interactive elements (modals, dropdowns, tooltips, tabs)
|
||||
- Using `<div>` or `<span>` with `onClick`
|
||||
- Adding `aria-*` attributes to any element
|
||||
- Implementing keyboard navigation or focus management
|
||||
- Receiving accessibility feedback from code review tools (CodeRabbit, ESLint a11y)
|
||||
- Building components that must support screen readers
|
||||
|
||||
## Form Accessibility
|
||||
|
||||
Missing `htmlFor` / `id` pairing and disconnected error messages are the most common issues flagged in code review.
|
||||
|
||||
### Label Connection
|
||||
|
||||
```tsx
|
||||
// BAD: label has no connection to input — screen readers cannot associate them
|
||||
<label>Email</label>
|
||||
<input type="email" />
|
||||
|
||||
// GOOD: htmlFor matches input id
|
||||
<label htmlFor="email">Email</label>
|
||||
<input id="email" type="email" />
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
```tsx
|
||||
// BAD: visual-only asterisk conveys nothing to screen readers
|
||||
<label htmlFor="email">Email *</label>
|
||||
<input id="email" type="email" />
|
||||
|
||||
// GOOD: required enables native browser validation; aria-required signals it to screen readers
|
||||
<label htmlFor="email">
|
||||
Email <span aria-hidden="true">*</span>
|
||||
</label>
|
||||
<input id="email" type="email" required aria-required="true" />
|
||||
```
|
||||
|
||||
### Error Messages
|
||||
|
||||
```tsx
|
||||
// BAD: error text exists visually but is not linked to the input
|
||||
<input id="email" type="email" />
|
||||
<span className="error">Invalid email address</span>
|
||||
|
||||
// GOOD: aria-describedby connects input to its error message
|
||||
// aria-invalid signals the invalid state to screen readers
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
aria-describedby="email-error"
|
||||
aria-invalid={!!error}
|
||||
/>
|
||||
{error && (
|
||||
<span id="email-error" role="alert">
|
||||
{error}
|
||||
</span>
|
||||
)}
|
||||
```
|
||||
|
||||
### Complete Accessible Form
|
||||
|
||||
```tsx
|
||||
interface LoginFormProps {
|
||||
onSubmit: (email: string, password: string) => void;
|
||||
}
|
||||
|
||||
export function LoginForm({ onSubmit }: LoginFormProps) {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [errors, setErrors] = useState<{ email?: string; password?: string }>({});
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const newErrors: typeof errors = {};
|
||||
if (!email) newErrors.email = 'Email is required';
|
||||
if (!password) newErrors.password = 'Password is required';
|
||||
if (Object.keys(newErrors).length) {
|
||||
setErrors(newErrors);
|
||||
return;
|
||||
}
|
||||
onSubmit(email, password);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} noValidate>
|
||||
<div>
|
||||
<label htmlFor="email">
|
||||
Email <span aria-hidden="true">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
aria-required="true"
|
||||
aria-describedby={errors.email ? 'email-error' : undefined}
|
||||
aria-invalid={!!errors.email}
|
||||
autoComplete="email"
|
||||
/>
|
||||
{errors.email && (
|
||||
<span id="email-error" role="alert">
|
||||
{errors.email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="password">
|
||||
Password <span aria-hidden="true">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
aria-required="true"
|
||||
aria-describedby={errors.password ? 'password-error' : undefined}
|
||||
aria-invalid={!!errors.password}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
{errors.password && (
|
||||
<span id="password-error" role="alert">
|
||||
{errors.password}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button type="submit">Log in</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Semantic HTML
|
||||
|
||||
Use the element that matches the intent. Screen readers and keyboard users depend on native semantics.
|
||||
|
||||
```tsx
|
||||
// BAD: div has no role, no keyboard support, no accessible name
|
||||
<div onClick={handleClick}>Submit</div>
|
||||
|
||||
// GOOD: button is focusable, activates on Enter/Space, announces as "button"
|
||||
<button type="button" onClick={handleClick}>Submit</button>
|
||||
```
|
||||
|
||||
```tsx
|
||||
// BAD: non-semantic navigation
|
||||
<div onClick={() => navigate('/home')}>Home</div>
|
||||
|
||||
// GOOD: anchor supports right-click, middle-click, and keyboard navigation
|
||||
<a href="/home">Home</a>
|
||||
```
|
||||
|
||||
```tsx
|
||||
// BAD: heading hierarchy skipped (h1 to h4)
|
||||
<h1>Dashboard</h1>
|
||||
<h4>Recent Activity</h4>
|
||||
|
||||
// GOOD: sequential heading levels
|
||||
<h1>Dashboard</h1>
|
||||
<h2>Recent Activity</h2>
|
||||
```
|
||||
|
||||
## ARIA Attributes
|
||||
|
||||
Use ARIA only when native HTML semantics are insufficient. Wrong ARIA is worse than no ARIA.
|
||||
|
||||
### aria-label vs aria-labelledby
|
||||
|
||||
```tsx
|
||||
// aria-label: inline string label — use when no visible label text exists
|
||||
<button aria-label="Close modal">
|
||||
<XIcon />
|
||||
</button>
|
||||
|
||||
// aria-labelledby: references another element's text — use when a visible label exists
|
||||
<section aria-labelledby="section-title">
|
||||
<h2 id="section-title">Recent Orders</h2>
|
||||
{/* content */}
|
||||
</section>
|
||||
```
|
||||
|
||||
### aria-describedby
|
||||
|
||||
```tsx
|
||||
// Provides supplementary description beyond the label
|
||||
<button
|
||||
aria-describedby="delete-warning"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
Delete account
|
||||
</button>
|
||||
<p id="delete-warning">This action cannot be undone.</p>
|
||||
```
|
||||
|
||||
### aria-live for Dynamic Content
|
||||
|
||||
```tsx
|
||||
// Use aria-live to announce content that updates without a page reload
|
||||
// polite: waits for user to finish current action before announcing
|
||||
// assertive: interrupts immediately — use only for urgent errors
|
||||
|
||||
export function StatusMessage({ message, isError }: { message: string; isError?: boolean }) {
|
||||
return (
|
||||
<div role="status" aria-live={isError ? 'assertive' : 'polite'} aria-atomic="true">
|
||||
{message}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### aria-expanded and aria-controls
|
||||
|
||||
```tsx
|
||||
export function Accordion({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const contentId = useId();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button aria-expanded={isOpen} aria-controls={contentId} onClick={() => setIsOpen(prev => !prev)}>
|
||||
{title}
|
||||
</button>
|
||||
<div id={contentId} hidden={!isOpen}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Keyboard Navigation
|
||||
|
||||
Every interactive element must be reachable and operable by keyboard alone.
|
||||
|
||||
### Custom Dropdown
|
||||
|
||||
```tsx
|
||||
export function Dropdown({ options, onSelect }: { options: string[]; onSelect: (value: string) => void }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const listId = useId();
|
||||
|
||||
if (!options.length) return null;
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
setActiveIndex(i => Math.min(i + 1, options.length - 1));
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
setActiveIndex(i => Math.max(i - 1, 0));
|
||||
break;
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
e.preventDefault();
|
||||
if (isOpen) onSelect(options[activeIndex]);
|
||||
setIsOpen(prev => !prev);
|
||||
break;
|
||||
case 'Escape':
|
||||
setIsOpen(false);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
role="combobox"
|
||||
aria-expanded={isOpen}
|
||||
aria-haspopup="listbox"
|
||||
aria-controls={listId}
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={() => setIsOpen(prev => !prev)}
|
||||
>
|
||||
<span>{options[activeIndex]}</span>
|
||||
{isOpen && (
|
||||
<ul id={listId} role="listbox">
|
||||
{options.map((option, index) => (
|
||||
<li
|
||||
key={option}
|
||||
role="option"
|
||||
aria-selected={index === activeIndex}
|
||||
onClick={() => {
|
||||
onSelect(option);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Focus Management
|
||||
|
||||
Focus must move logically when UI state changes — especially for modals and route transitions.
|
||||
|
||||
### Modal Focus Restoration
|
||||
|
||||
> This example covers initial focus and restoration. For a full focus trap (Tab/Shift+Tab cycling within the modal), use a library like [`focus-trap-react`](https://github.com/focus-trap/focus-trap-react) which handles edge cases like dynamic content and nested portals.
|
||||
|
||||
```tsx
|
||||
export function Modal({ isOpen, onClose, title, children }: { isOpen: boolean; onClose: () => void; title: string; children: React.ReactNode }) {
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
const previousFocusRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
// Save currently focused element and move focus into modal
|
||||
previousFocusRef.current = document.activeElement as HTMLElement;
|
||||
modalRef.current?.focus();
|
||||
} else {
|
||||
// Restore focus to the element that opened the modal
|
||||
previousFocusRef.current?.focus();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div ref={modalRef} role="dialog" aria-modal="true" aria-labelledby="modal-title" tabIndex={-1} onKeyDown={e => e.key === 'Escape' && onClose()}>
|
||||
<h2 id="modal-title">{title}</h2>
|
||||
{children}
|
||||
<button onClick={onClose}>Close</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Images and Icons
|
||||
|
||||
```tsx
|
||||
// BAD: decorative icon announced as unlabeled image
|
||||
<img src="/icon.svg" />
|
||||
|
||||
// GOOD: decorative image hidden from screen readers
|
||||
<img src="/decoration.png" alt="" aria-hidden="true" />
|
||||
|
||||
// GOOD: meaningful image with descriptive alt text
|
||||
<img src="/chart.png" alt="Monthly revenue increased 23% from January to March" />
|
||||
|
||||
// GOOD: icon button with accessible label
|
||||
<button aria-label="Delete item">
|
||||
<TrashIcon aria-hidden="true" />
|
||||
</button>
|
||||
```
|
||||
|
||||
## Reduced Motion
|
||||
|
||||
Respect users who have requested reduced motion in their OS settings.
|
||||
|
||||
```tsx
|
||||
export function useReducedMotion(): boolean {
|
||||
const [prefersReduced, setPrefersReduced] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
setPrefersReduced(mq.matches);
|
||||
const handler = (e: MediaQueryListEvent) => setPrefersReduced(e.matches);
|
||||
mq.addEventListener('change', handler);
|
||||
return () => mq.removeEventListener('change', handler);
|
||||
}, []);
|
||||
|
||||
return prefersReduced;
|
||||
}
|
||||
|
||||
// Usage
|
||||
export function AnimatedCard({ children }: { children: React.ReactNode }) {
|
||||
const reduceMotion = useReducedMotion();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
transition: reduceMotion ? 'none' : 'transform 300ms ease'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
```tsx
|
||||
// BAD: onClick on non-interactive element with no keyboard support
|
||||
<div onClick={handleClick}>Click me</div>
|
||||
|
||||
// BAD: aria-label on a div that has no role
|
||||
<div aria-label="Navigation">...</div>
|
||||
|
||||
// BAD: placeholder used as a substitute for label
|
||||
<input placeholder="Enter your email" />
|
||||
|
||||
// BAD: positive tabIndex creates unpredictable tab order
|
||||
<button tabIndex={3}>Submit</button>
|
||||
|
||||
// BAD: aria-hidden on a focusable element — keyboard users get trapped
|
||||
<button aria-hidden="true">Open</button>
|
||||
|
||||
// BAD: role="button" on div without keyboard handler
|
||||
<div role="button" onClick={handleClick}>Submit</div>
|
||||
// Missing: tabIndex={0}, onKeyDown for Enter/Space
|
||||
```
|
||||
|
||||
## Checklist
|
||||
|
||||
Before submitting any interactive component for review:
|
||||
|
||||
- [ ] Every `<input>`, `<select>`, and `<textarea>` has a connected `<label>` via `htmlFor`/`id`
|
||||
- [ ] Error messages are linked with `aria-describedby` and marked `role="alert"`
|
||||
- [ ] No `onClick` on `<div>` or `<span>` without `role`, `tabIndex`, and `onKeyDown`
|
||||
- [ ] Icon-only buttons have `aria-label`
|
||||
- [ ] Decorative images use `alt=""` and `aria-hidden="true"`
|
||||
- [ ] Modals restore focus on close (for full focus trapping with Tab/Shift+Tab cycling, use a library like `focus-trap-react`)
|
||||
- [ ] Dynamic content updates use `aria-live`
|
||||
- [ ] `prefers-reduced-motion` is respected for animations
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `frontend-patterns` — general React component and state patterns
|
||||
- `design-system` — design token and component consistency
|
||||
- `motion-ui` — animation patterns with accessibility considerations
|
||||
@@ -50,7 +50,6 @@ function runTests() {
|
||||
const components = listInstallComponents({ family: 'locale' });
|
||||
assert.ok(components.some(component => component.id === 'locale:ja'));
|
||||
assert.ok(components.some(component => component.id === 'locale:zh-cn'));
|
||||
assert.ok(components.some(component => component.id === 'locale:de-de'));
|
||||
assert.ok(components.every(component => component.family === 'locale'));
|
||||
})) passed++; else failed++;
|
||||
|
||||
@@ -76,59 +75,6 @@ function runTests() {
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('locale:de-de resolves to the German translated docs module', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-plan-de-'));
|
||||
try {
|
||||
const plan = resolveInstallPlan({
|
||||
includeComponentIds: ['locale:de-de'],
|
||||
target: 'claude',
|
||||
homeDir,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(plan.selectedModuleIds, ['docs-de-de']);
|
||||
assert.ok(
|
||||
plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/de-DE'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/de-DE')
|
||||
)),
|
||||
'Should map docs/de-DE to ~/.claude/docs/de-DE'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale de dry-run includes docs-de-de operations', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-de-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-de-project-'));
|
||||
|
||||
try {
|
||||
const output = runInstallApply([
|
||||
'--locale', 'de',
|
||||
'--dry-run',
|
||||
'--json',
|
||||
], {
|
||||
cwd: projectDir,
|
||||
env: { HOME: homeDir },
|
||||
});
|
||||
const json = JSON.parse(output);
|
||||
|
||||
assert.strictEqual(json.plan.mode, 'manifest');
|
||||
assert.deepStrictEqual(json.plan.includedComponentIds, ['locale:de-de']);
|
||||
assert.deepStrictEqual(json.plan.selectedModuleIds, ['docs-de-de']);
|
||||
assert.ok(
|
||||
json.plan.operations.some(operation => (
|
||||
normalizePlanPath(operation.sourceRelativePath) === 'docs/de-DE/README.md'
|
||||
&& normalizePlanPath(operation.destinationPath).endsWith('/.claude/docs/de-DE/README.md')
|
||||
)),
|
||||
'Should copy translated README into ~/.claude/docs/de-DE'
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(homeDir, { recursive: true, force: true });
|
||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('end-to-end: --locale ja dry-run includes docs-ja-jp operations', () => {
|
||||
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-'));
|
||||
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locale-dry-run-project-'));
|
||||
|
||||
Reference in New Issue
Block a user