feat: register a global form theme and switch the locale to German

This commit is contained in:
fromme committed 2026-09-13 15:18:19 +02:00
1 parent ca57df7437
commit f4741e1bee
6 files changed
+172 -3

No files matched your search

+1
View File
@@ -43,6 +43,7 @@
"symfony/web-link": "7.4.*",
"symfony/yaml": "7.4.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/intl-extra": "^3.26",
"twig/twig": "^2.12|^3.0"
},
"config": {
Generated
+65 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ef19a7def0151d8b452378a05ec4c324",
"content-hash": "3e68f01587473077081d93ce2360e229",
"packages": [
{
"name": "composer/semver",
@@ -7888,6 +7888,70 @@
],
"time": "2026-02-07T08:07:38+00:00"
},
{
"name": "twig/intl-extra",
"version": "v3.26.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/intl-extra.git",
"reference": "98f5ad5bff13230fcd2d834d9e79b50adf3ccda9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/intl-extra/zipball/98f5ad5bff13230fcd2d834d9e79b50adf3ccda9",
"reference": "98f5ad5bff13230fcd2d834d9e79b50adf3ccda9",
"shasum": ""
},
"require": {
"php": ">=8.1.0",
"symfony/intl": "^5.4|^6.4|^7.0|^8.0",
"twig/twig": "^3.13|^4.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Twig\\Extra\\Intl\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
}
],
"description": "A Twig extension for Intl",
"homepage": "https://twig.symfony.com",
"keywords": [
"intl",
"twig"
],
"support": {
"source": "https://github.com/twigphp/intl-extra/tree/v3.26.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2026-05-19T20:44:48+00:00"
},
{
"name": "twig/twig",
"version": "v3.28.0",
+1 -1
View File
@@ -1,5 +1,5 @@
framework:
default_locale: en
default_locale: de
translator:
default_path: '%kernel.project_dir%/translations'
providers:
+2
View File
@@ -1,5 +1,7 @@
twig:
file_name_pattern: '*.twig'
# One theme for the whole app, so it is registered globally rather than per-template.
form_themes: ['forms.html.twig']
when@test:
twig:
+1 -1
View File
@@ -968,7 +968,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* enabled?: bool|Param, // Default: false
* },
* intl?: bool|array{
* enabled?: bool|Param, // Default: false
* enabled?: bool|Param, // Default: true
* },
* cssinliner?: bool|array{
* enabled?: bool|Param, // Default: false
+102
View File
@@ -0,0 +1,102 @@
{#
Ported from myep's forms_admin.html.twig, trimmed to the blocks this app actually has.
Registered globally in config/packages/twig.yaml rather than per-template: myep applies it
with {% form_theme %} because it carries two themes, we only have one.
Deliberately not ported: datepicker_widget, autocomplete_widget, multiselect_widget,
money_widget, birthday_widget, abbreviated_date_widget -- all back myep-specific form types
and Stimulus controllers that do not exist here.
#}
{% use 'form_div_layout.html.twig' %}
{%- block form_row -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~ "_help"}} -%}
{%- endif -%}
<div{% with {attr: row_attr} %}{{ block('attributes') }}{% endwith %}>
{{- form_label(form) -}}
{{- form_widget(form, widget_attr) -}}
{{- form_errors(form) -}}
{{- form_help(form) -}}
</div>
{%- endblock form_row -%}
{%- block form_label -%}
{% set class = 'block font-bold pb-2' %}
{% if errors|length %}
{% set class = class ~ ' text-red-500' %}
{% endif %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' ' ~ class)|trim}) %}
{{ parent() }}
{%- endblock form_label -%}
{%- block form_errors -%}
{%- if errors|length > 0 -%}
<ul class="pb-2">
{%- for error in errors -%}
<li class="text-red-500">{{ error.message }}</li>
{%- endfor -%}
</ul>
{%- endif -%}
{%- endblock form_errors -%}
{# The field class is repeated in each block on purpose: a top-level {% set %} in a form theme
is not in scope inside its blocks, because each block is rendered with the caller's context. #}
{%- block form_widget_simple -%}
{%- set type = type|default('text') -%}
{%- if type != 'hidden' -%}
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset text-sm')|trim }) -%}
{%- if errors|length -%}
{%- set attr = attr|merge({'class': attr.class ~ ' ring-red-500 placeholder-red-500 focus:ring-red-500' }) -%}
{%- else -%}
{%- set attr = attr|merge({'class': attr.class ~ ' placeholder:text-gray-400 focus:ring-primary' }) -%}
{%- endif -%}
{%- if disabled is defined and disabled -%}
{%- set attr = attr|merge({'class': attr.class ~ ' cursor-not-allowed' }) -%}
{%- endif -%}
{%- endif -%}
{{ parent() }}
{%- endblock form_widget_simple -%}
{%- block textarea_widget -%}
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset text-sm')|trim }) -%}
{%- if errors|length -%}
{%- set attr = attr|merge({'class': attr.class ~ ' ring-red-500 placeholder-red-500 focus:ring-red-500' }) -%}
{%- else -%}
{%- set attr = attr|merge({'class': attr.class ~ ' placeholder:text-gray-400 focus:ring-primary' }) -%}
{%- endif -%}
{{ parent() }}
{%- endblock textarea_widget -%}
{%- block choice_widget_collapsed -%}
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset text-sm')|trim }) -%}
{%- if errors|length -%}
{%- set attr = attr|merge({'class': attr.class ~ ' ring-red-500 focus:ring-red-500' }) -%}
{%- else -%}
{%- set attr = attr|merge({'class': attr.class ~ ' focus:ring-primary' }) -%}
{%- endif -%}
{{ parent() }}
{%- endblock choice_widget_collapsed -%}
{%- block checkbox_widget -%}
{%- set attr = attr|merge({'class': (attr.class|default('') ~ ' h-4 w-4 rounded text-primary')|trim }) -%}
{%- if errors|length -%}
{%- set attr = attr|merge({'class': attr.class ~ ' border-red-500 text-red-500 focus:ring-red-500' }) -%}
{%- else -%}
{%- set attr = attr|merge({'class': attr.class ~ ' border-gray-300 focus:ring-primary' }) -%}
{%- endif -%}
{{ parent() }}
{%- endblock checkbox_widget -%}
{% block checkbox_row %}
<div class="relative flex items-start">
<div class="flex h-6 items-center">
{{ form_widget(form) }}
</div>
<div class="ml-3 leading-6 {{ errors|length ? 'text-red-500' : '' }}">
<label for="{{ form.vars.id }}">{{ form.vars.label }}</label>
{{- form_errors(form) -}}
</div>
</div>
{% endblock %}