i18n
Skill16 starsChanged 3 days agoApache-2.0View on GitHub
Comprehensive i18n reference and validation. Covers the dual i18n architecture (frontend Nuxt i18n + backend python-i18n), LocaleHandler/LocaleString class hierarchies, translation file structure and naming, scope inheritance, and when to create vs extend locale files. Also validates key consistency across locales and scans for hardcoded strings. Use when user says 'how does i18n work', 'add translations', 'create locale file', 'check translations', 'find missing i18n keys', 'validate locales', 'i18n coverage', or 'any hardcoded strings'. Do not use for frontend-only i18n config questions — see packages/web/CLAUDE.md instead.
We split this skill into the rules it gives an agent
8 rules. 0 are common, 5 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 36 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 9
All user-facing strings must be translated into 4 locales: de (German), en (English), fr (French), it (Italian).
- Very specific: line 21
Navigation: ALL routes MUST use localePath() — URLs include locale prefix (/en/service/agents)
- Distinctive: line 53
Every translation file MUST have exactly 4 variants — one per locale:
- Distinctive: line 75
Create a new file: when:
- Distinctive: line 81
Extend an existing file: when:
- Very specific: line 145
Key insight: All sub-package handlers call super().get_locale_paths(), which includes packages/core translations.
- Distinctive: line 222
All 4 locales MUST be provided.
- Distinctive: line 234
Run the deterministic validation script to compare YAML keys across locales:
“Common” is measured: kept by at least 6 in 10 of the 36 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Internationalization (i18n)
All user-facing strings must be translated into 4 locales: de (German), en (English), fr (French), it
(Italian). English (en) is the reference/default locale. Fallback chain: requested locale -> en -> first available.
Architecture: Two Separate Systems
Frontend and backend use completely independent i18n systems. They share no files, no configuration, and no runtime.
Frontend (Nuxt @nuxtjs/i18n)
- Config:
packages/web/nuxt.config.ts(i18n section,strategy: 'prefix',lazy: true) - Files:
packages/web/i18n/locales/{locale}.yaml— one mega YAML per locale (.yamlextension) - Usage:
$t('key.path')in templates,t('key.path')in<script setup>viauseI18n() - Navigation: ALL routes MUST use
localePath()— URLs include locale prefix (/en/service/agents) - Key structure: Nested YAML, accessed via dot-notation:
common.actions.save->{ common: { actions: { save: "Save" } } }
Backend (python-i18n library)
- Files:
{scope}/{name}.{locale}.ymlacross multiple packages (.ymlextension) - Usage:
locale_handler("scope.name.key.path")at runtime,ScopeLocaleString.from_i18n_path("scope.name.key")at definition time - Key structure: First two dot segments are
{scope}.{filename}, the rest navigate YAML nesting
Backend Translation Files
File Locations
| Package | Translation Directory | Scope Prefix |
packages/core | packages/core/swiss_ai_hub/core/i18n/translations/lib/ | lib |
packages/core | packages/core/swiss_ai_hub/core/i18n/translations/bot/ | bot |
packages/api | packages/api/swiss_ai_hub/api/i18n/translations/api/ | api |
packages/agent | packages/agent/swiss_ai_hub/agent/i18n/translations/agent/ | agent |
packages/process | packages/process/swiss_ai_hub/process/i18n/translations/process/ | process |
Bot exception: Bot translations live under packages/core (scope bot/), NOT in packages/bot. Bots use the base
LocaleHandler, not a bot-specific subclass.
Naming Convention
{scope}/{descriptive_name}.{locale}.ymlEvery translation file MUST have exactly 4 variants — one per locale:
agent/rag_agent.de.yml
agent/rag_agent.en.yml
agent/rag_agent.fr.yml
agent/rag_agent.it.ymlPath Resolution
The dot-notation path agent.rag_agent.metadata.name resolves as:
agent-> scope directory namerag_agent-> YAML filename (without locale/extension)metadata.name-> nested keys inside the YAML file
The system searches all registered load_path directories for agent/rag_agent.{locale}.yml, then navigates
data["metadata"]["name"].
When to Create a New File vs. Extend an Existing One
Create a new file when:
- Adding a new agent ->
agent/{agent_name}.{locale}.ymlfor metadata/steps/config labels - Adding a new process ->
process/{process_name}.{locale}.yml - Adding a new logical domain that doesn't fit existing groupings (e.g., a new guard type, a new controller)
Extend an existing file when:
- Adding keys to an existing agent/process (e.g., new step in
agent/rag_agent.en.yml) - Adding common/shared translations ->
lib/common.{locale}.ymlorapi/common.{locale}.yml - Adding event translations ->
lib/events.{locale}.yml - Adding guard translations ->
lib/guards.{locale}.yml
Naming guidance: Group by the thing being described, not by where it's used. Agent metadata, step names, config
labels, and error messages for the same agent all go in one file (e.g., agent/rag_agent.{locale}.yml). If a file grows
too large (>200 keys), split by sub-domain (e.g., agent/rag_agent_config.{locale}.yml).
Example File Structure
agent/rag_agent.en.yml:
metadata:
name: "RAG Agent"
description: "Retrieves relevant documents and generates answers."
steps:
retrieve_nodes:
name: "Retrieve Documents"
description: "Searches knowledge bases for relevant content."
config:
context_prompt:
label: "Context Prompt"
help: "System prompt used when generating answers."Accessed as: agent.rag_agent.metadata.name, agent.rag_agent.steps.retrieve_nodes.name, etc.
LocaleHandler Hierarchy
LocaleHandler is the base class for runtime translation lookup. Each sub-package extends it to register its own
translation directory while inheriting lib-level translations.
Base: LocaleHandler (packages/core/swiss_ai_hub/core/i18n/locale_handler.py)
DEFAULT_LOCALE = "en",LOCALE_WHITE_LIST = ["de", "en", "fr", "it"]get_locale_paths()returns[packages/core/swiss_ai_hub/core/i18n/translations/]__call__(key, locale)->i18n.t(key, locale=locale)— translates a keyt_object(key, locale)-> returns raw YAML data (dict/list) instead of stringextract(locale_data, locale)-> extracts fromdict[str, Any]orLocaleStringobjectsin_locale(locale)-> returns new handler instance for a different locale
Sub-package Handlers
Each extends LocaleHandler and overrides get_locale_paths() to add its own translation directory:
ApiLocaleHandler (packages/api/swiss_ai_hub/api/i18n/api_locale_handler.py):
def get_locale_paths(self) -> list[str]:
return [*super().get_locale_paths(), self_translations_path]Load paths: [lib/translations/, api/translations/] -> can resolve both lib.* and api.* keys.
AgentLocaleHandler (packages/agent/swiss_ai_hub/agent/i18n/agent_locale_handler.py): Same pattern. Load paths:
[lib/translations/, agent/translations/].
ProcessLocaleHandler (packages/process/swiss_ai_hub/process/i18n/process_locale_handler.py): Same pattern. Load
paths: [lib/translations/, process/translations/].
Key insight: All sub-package handlers call super().get_locale_paths(), which includes packages/core
translations. This means agent code can reference lib.events.start_event.name or lib.guards.context_guard.reason —
lib-level translations are always available in sub-packages.
Runtime Usage
In agent/process @step methods, the dispatcher injects a locale-aware handler:
async def my_step(self, event: UserMessageEvent, t: AgentLocaleHandler) -> StopEvent:
error_msg = t("agent.my_agent.errors.not_found")
lib_msg = t("lib.common.test") # lib keys work too
return StopEvent(output=error_msg)LocaleString Hierarchy
LocaleString holds pre-resolved translations for all 4 locales in a single Pydantic model. Used at definition time
(class attributes, config labels, event metadata).
Base: LocaleString (packages/core/swiss_ai_hub/core/i18n/locale_string.py)
Fields: de: str | None, en: str | None, fr: str | None, it: str | None
Key methods:
in_locale(locale)-> returns string for that localefrom_i18n_path(path)-> creates instance by callingLocaleHandler(locale)(path)for each localeas_form(label, ...)-> creates aLocaleInputform element for multi-language editing
Sub-package LocaleStrings
Each sub-package has its own LocaleString subclass that uses the package-specific LocaleHandler:
AgentLocaleString (packages/agent/swiss_ai_hub/agent/i18n/agent_locale_string.py):
@classmethod
def from_i18n_path(cls, path: str) -> Self:
return cls(
de=AgentLocaleHandler("de")(path),
en=AgentLocaleHandler("en")(path),
fr=AgentLocaleHandler("fr")(path),
it=AgentLocaleHandler("it")(path),
)ApiLocaleString (packages/api/swiss_ai_hub/api/i18n/api_locale_string.py): Uses ApiLocaleHandler.
ProcessLocaleString (packages/process/swiss_ai_hub/process/i18n/process_locale_string.py): Uses
ProcessLocaleHandler.
Definition-Time Usage
Agent/process metadata and config labels use from_i18n_path():
class RetrievalAgent(BaseAgent):
name: ClassVar[AgentLocaleString] = AgentLocaleString.from_i18n_path(
"agent.retrieval_agent.metadata.name"
)
@step(
name=AgentLocaleString.from_i18n_path("agent.retrieval_agent.steps.retrieve.name"),
description=AgentLocaleString.from_i18n_path("agent.retrieval_agent.steps.retrieve.description"),
)
async def retrieve(self, ...) -> ...:Direct Construction
For inline values that don't come from YAML files:
LocaleString(de="Hallo", en="Hello", fr="Bonjour", it="Ciao")All 4 locales MUST be provided. This is common in event classes and form elements.
Persistence: LocaleStringEntity
LocaleStringEntity (packages/core/swiss_ai_hub/core/persistence/i18n/locale_string_entity.py) is a MongoEngine
EmbeddedDocument with the same 4 fields. Convert between them:
LocaleStringEntity.from_locale_string(locale_string)-> for storageentity.to_locale_string()-> for runtime
Validation: Run the Script
Run the deterministic validation script to compare YAML keys across locales:
uv run python .claude/skills/i18n/scripts/validate-i18n.py $ARGUMENTS$ARGUMENTS: frontend, backend, or all (default).
The script flattens nested YAML keys to dot-notation, uses English as reference, and reports missing/extra/empty keys with coverage percentages. Present the script output to the user as-is.
Validation: LocaleString Completeness
The script does not cover inline LocaleString(...) instances. Check manually:
grep -rn 'LocaleString(' packages/agent/ packages/process/ --include='*.py'Each LocaleString(...) must have all 4 keyword arguments: de=, en=, fr=, it=.
Validation: Hardcoded Strings in New Code
Review git diff main -- '*.py' '*.vue' '*.ts' for hardcoded user-facing strings.
Frontend: Flag literal text in HTML elements, hardcoded label=/placeholder=/title= props, toast messages
without $t() or t().
Backend: Flag LocaleString() with fewer than 4 locales, hardcoded strings in
display_chunk()/display_thought(), literal form element label=/help= without LocaleString.
Do NOT flag: Log messages, internal exceptions, test files, comments, NATS subjects, config keys, docstrings.
Validation: Frontend Template Key Usage
Extract i18n keys from Vue templates and verify they exist in en.yaml:
grep -rhoP "\$t\(['\"]([^'\"]+)['\"]\)" packages/web/ --include='*.vue' | sort -uIgnore dynamic keys like $t(variable).
Other versions45 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 45
- lobehub/lobe-chat★ 84ksame name
- lobehub/lobehub★ 84ksame name
- iOfficeAI/AionUi★ 34ksame name
- massCodeIO/massCode★ 7.1ksame name
- leookun/cursor-byok★ 3.2ksame name
- Pixeval/Pixeval★ 3.2ksame name
- akiver/cs-demo-manager★ 2ksame name
- d-kimuson/claude-code-viewer★ 1.3ksame name
- huoshen80/ReinaManager★ 728same name
- OpenClaudia/openclaudia-skills★ 724same name
35 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use oss-pr, pr-automation and 9 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
CES-LtdSkilloss-pr
Use when creating a pull request, after committing changes, or when user invokes /oss-pr. Covers branch management, quality checks, commit, push, and PR creation.
Also in 3 projects that use this
CES-LtdSkillpr-automation
PR Automation Orchestrator: poll open PRs, check CI, run review, fix, and merge eligible PRs. Use when: (1) Invoked by daemon via scripts/pr-automation.sh, (2) User says "/pr-automation".
Also in 3 projects that use this
volovelySkillpr-fix
This skill should be used when the user asks to "fix PR comments", "address PR feedback", "resolve PR comments", provides a GitHub PR URL with intent to fix, or says "pr-fix". It reads all review comments on a PR, decides which need code fixes vs. replies, makes the fixes, and posts replies — all with explicit user approval before any GitHub action.
Also in 3 projects that use this
xfstudioSkillgraphql
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.
Also in 3 projects that use this
MicrosoftSkillbump-version
Bump the VoxelPic version to a user-specified value. USE FOR: setting or updating the project version across all files that embed it. Applies to requests like 'bump version to X.Y.Z', 'set version', or 'update version'.
Also in 4 projects that use this
VercelSkillreact
React renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
Also in 4 projects that use this
- +2 more from CES-Ltd
In this repository50 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- docs/CLAUDE.mdCLAUDE.md
- .github/actions/CLAUDE.mdCLAUDE.md
- arc42Skill
- audit-frontendSkill
- bot-frameworkSkill
- create-or-audit-claude-mdSkill
- create-or-audit-skillSkill
- create-or-audit-subagentSkill
- create-prSkill
- dagster-pipelinesSkill
- debug-agentSkill
- debug-frontendSkill
- debug-pipelineSkill
- design-systemSkill
- docker-devSkill
- document-decisionSkill
- document-featureSkill
- explainSkill
- generate-sdkSkill
- implement-feedback-from-prSkill
- likec4-dslSkill
- lintSkill
- merge-mainSkill
- nats-eventsSkill
- plan-issueSkill
- pr-demo-videoSkill
- primevue-lookupSkill
- rclone-guideSkill
- reflectSkill
- review-diffSkill
- scaffold-agentSkill
- scaffold-api-endpointSkill
- scaffold-api-repositorySkill
- scaffold-api-serviceSkill
- scaffold-bot-handlerSkill
- scaffold-composableSkill
- scaffold-event-displaySkill
- scaffold-frontend-componentSkill
- scaffold-frontend-pageSkill
- scaffold-frontend-subpageSkill
- scaffold-pipelineSkill
- setup-bot-connectionSkill
- splice-issueSkill
- sync-agent-docsSkill
- test-scopeSkill
- update-docSkill
- verify-sdk-syncSkill
- write-docSkill
- write-issueSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

