ACTIVATE when writing or modifying Twig templates, using Twig components (twig:*), handling translations in Twig, or debugging translation issues. ACTIVATE whenever 'trans_default_domain', 'twig component', or 'translation not working' appears. Covers: trans_default_domain isolation in Twig components (critical pitfall), ClockInterface for dates in templates. DO NOT use for: Twig syntax basics, Symfony controller rendering, CSS/HTML questions.
From phpnpx claudepluginhub fabiensalles/claude-marketplace --plugin phpThis skill uses the workspace's default tool permissions.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Designs KPI dashboards with metrics selection (MRR, churn, LTV/CAC), visualization best practices, real-time monitoring, and hierarchy for executives, operations, and product teams.
Transforms raw data into narratives with story structures, visuals, and frameworks for executive presentations, analytics reports, and stakeholder communications.
Two critical pitfalls that produce silent bugs in Twig templates.
IMPORTANT: Twig components (<twig:*>) are isolated and do NOT inherit trans_default_domain from the parent template.
When using trans_default_domain in a parent template, child content passed to a Twig component does NOT inherit this domain:
{# Parent template #}
{% trans_default_domain 'my_domain' %}
<twig:Button>
{{ 'my_key'|trans }} {# WRONG: Will look in 'messages' domain, not 'my_domain' #}
</twig:Button>
Always specify the domain explicitly when translating inside Twig component content:
{% trans_default_domain 'my_domain' %}
<twig:Button>
{{ 'my_key'|trans(domain: 'my_domain') }} {# CORRECT: Explicit domain #}
</twig:Button>
Twig components process their content in isolation. The trans_default_domain tag sets a variable in the current template scope, but component content is evaluated in a separate context where this variable is not accessible.
{% extends 'base.html.twig' %}
{% block body %}
{% trans_default_domain 'order_checkout' %}
{# Direct translation - uses trans_default_domain #}
<h1>{{ 'title'|trans }}</h1>
{# Inside a Twig component - MUST specify domain #}
<div class="d-flex gap-3">
<twig:Button href="{{ path('back_route') }}">
{{ 'back_button'|trans(domain: 'order_checkout') }}
</twig:Button>
<twig:Button type="submit" color="primary">
{{ 'continue_button'|trans(domain: 'order_checkout') }}
</twig:Button>
</div>
{% endblock %}
IMPORTANT: Never use Twig date functions directly in templates. Inject a ClockInterface (PSR-20) via a Twig component, a controller, or a Twig function/extension.
{# WRONG: Global function in the template #}
<footer>Acme {{ "now"|date("Y") }}</footer>
Issues:
// src/Twig/Component/Layout.php
final class Layout
{
public function __construct(private readonly ClockInterface $clock) {}
public function getCurrentYear(): string
{
return $this->clock->now()->format('Y');
}
}
<footer>Acme {{ this.currentYear }}</footer>
// In the controller
return $this->render('template.html.twig', [
'currentYear' => $this->clock->now()->format('Y'),
]);
<footer>Acme {{ currentYear }}</footer>
// src/Twig/Extension/DateExtension.php
final class DateExtension extends AbstractExtension
{
public function __construct(private readonly ClockInterface $clock) {}
public function getFunctions(): array
{
return [
new TwigFunction('current_year', [$this, 'getCurrentYear']),
];
}
public function getCurrentYear(): string
{
return $this->clock->now()->format('Y');
}
}
<footer>Acme {{ current_year() }}</footer>
Psr\Clock\ClockInterface)Always use explicit domain: parameter when:
<twig:*> component tags| Context | Inherits trans_default_domain | Solution |
|---|---|---|
| Direct in template | Yes | {{ 'key'|trans }} |
Inside <twig:Component> | No | {{ 'key'|trans(domain: 'domain') }} |
| Inside macro (same file) | Yes | {{ 'key'|trans }} |
| Inside imported macro | Depends | Use explicit domain to be safe |
When a translation key appears as-is instead of translated:
translations/{domain}.{locale}.yaml existssection.subsection.keybin/console cache:clear