fix: improved language selector
This commit is contained in:
@@ -2,7 +2,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: crochet\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-20 09:18+0000\n"
|
||||
"POT-Creation-Date: 2026-07-20 10:32+0000\n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -47,35 +47,33 @@ msgstr "Create pattern"
|
||||
msgid "¿Seguro que quieres eliminar este patrón? No podrás deshacerlo."
|
||||
msgstr "Are you sure you want to delete this pattern? This cannot be undone."
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:34
|
||||
#: crochet/templates/crochet/account_home.html:37
|
||||
msgid "Patrón sin título"
|
||||
msgstr "Untitled pattern"
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:37
|
||||
#: crochet/templates/crochet/account_home.html:41
|
||||
#, python-format
|
||||
msgid "Actualizado el %(date)s"
|
||||
msgstr "Updated on %(date)s"
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:40
|
||||
#: crochet/templates/crochet/pattern.html:33
|
||||
msgid "Ver patrón"
|
||||
msgstr "View pattern"
|
||||
#: crochet/templates/crochet/account_home.html:44
|
||||
#: crochet/templates/crochet/pattern.html:143
|
||||
#: crochet/templates/crochet/pattern.html:189
|
||||
msgid "Vista previa"
|
||||
msgstr "Preview"
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:41
|
||||
msgid "Editar"
|
||||
msgstr "Edit"
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:45
|
||||
#: crochet/templates/crochet/account_home.html:48
|
||||
#: crochet/templates/crochet/pattern.html:38
|
||||
msgid "Eliminar"
|
||||
msgstr "Delete"
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:54
|
||||
#: crochet/templates/crochet/account_home.html:57
|
||||
msgid "Todavía no tienes ningún patrón."
|
||||
msgstr "You don't have any patterns yet."
|
||||
|
||||
#: crochet/templates/crochet/account_settings.html:4
|
||||
#: crochet/templates/crochet/account_settings.html:18
|
||||
#: crochet/templates/crochet/base.html:50
|
||||
#: crochet/templates/crochet/base.html:52
|
||||
msgid "Ajustes de la cuenta"
|
||||
msgstr "Account settings"
|
||||
|
||||
@@ -84,21 +82,21 @@ msgid "Volver a mis patrones"
|
||||
msgstr "Back to my patterns"
|
||||
|
||||
#: crochet/templates/crochet/base.html:39
|
||||
msgid "Idioma"
|
||||
msgstr "Language"
|
||||
msgid "Cambiar idioma"
|
||||
msgstr "Change language"
|
||||
|
||||
#: crochet/templates/crochet/base.html:54
|
||||
#: crochet/templates/crochet/base.html:56
|
||||
msgid "Cerrar sesión"
|
||||
msgstr "Log out"
|
||||
|
||||
#: crochet/templates/crochet/base.html:60
|
||||
#: crochet/templates/crochet/base.html:62
|
||||
#: crochet/templates/crochet/home.html:24
|
||||
#: crochet/templates/registration/login.html:4
|
||||
#: crochet/templates/registration/login.html:14
|
||||
msgid "Iniciar sesión"
|
||||
msgstr "Log in"
|
||||
|
||||
#: crochet/templates/crochet/base.html:61
|
||||
#: crochet/templates/crochet/base.html:63
|
||||
#: crochet/templates/registration/register.html:29
|
||||
msgid "Registrarme"
|
||||
msgstr "Sign up"
|
||||
@@ -172,14 +170,14 @@ msgstr "Couldn't save. Please try again."
|
||||
msgid "Guardar"
|
||||
msgstr "Save"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:33
|
||||
msgid "Ver patrón"
|
||||
msgstr "View pattern"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:34
|
||||
msgid "Exportar a PDF"
|
||||
msgstr "Export to PDF"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:38
|
||||
msgid "Eliminar patrón"
|
||||
msgstr "Delete pattern"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:45
|
||||
msgid "Guardado"
|
||||
msgstr "Saved"
|
||||
@@ -291,11 +289,6 @@ msgstr "Landscape"
|
||||
msgid "Secciones"
|
||||
msgstr "Sections"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:143
|
||||
#: crochet/templates/crochet/pattern.html:189
|
||||
msgid "Vista previa"
|
||||
msgstr "Preview"
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:152
|
||||
msgid "Colapsar todo"
|
||||
msgstr "Collapse all"
|
||||
@@ -491,3 +484,12 @@ msgstr ""
|
||||
#: crochet/views.py:24
|
||||
msgid "Este patrón todavía no tiene contenido."
|
||||
msgstr "This pattern doesn't have any content yet."
|
||||
|
||||
#~ msgid "Idioma"
|
||||
#~ msgstr "Language"
|
||||
|
||||
#~ msgid "Editar"
|
||||
#~ msgstr "Edit"
|
||||
|
||||
#~ msgid "Eliminar patrón"
|
||||
#~ msgstr "Delete pattern"
|
||||
|
||||
@@ -2,7 +2,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: crochet\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-20 09:18+0000\n"
|
||||
"POT-Creation-Date: 2026-07-20 10:32+0000\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -47,35 +47,33 @@ msgstr ""
|
||||
msgid "¿Seguro que quieres eliminar este patrón? No podrás deshacerlo."
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:34
|
||||
#: crochet/templates/crochet/account_home.html:37
|
||||
msgid "Patrón sin título"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:37
|
||||
#: crochet/templates/crochet/account_home.html:41
|
||||
#, python-format
|
||||
msgid "Actualizado el %(date)s"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:40
|
||||
#: crochet/templates/crochet/pattern.html:33
|
||||
msgid "Ver patrón"
|
||||
#: crochet/templates/crochet/account_home.html:44
|
||||
#: crochet/templates/crochet/pattern.html:143
|
||||
#: crochet/templates/crochet/pattern.html:189
|
||||
msgid "Vista previa"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:41
|
||||
msgid "Editar"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:45
|
||||
#: crochet/templates/crochet/account_home.html:48
|
||||
#: crochet/templates/crochet/pattern.html:38
|
||||
msgid "Eliminar"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_home.html:54
|
||||
#: crochet/templates/crochet/account_home.html:57
|
||||
msgid "Todavía no tienes ningún patrón."
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/account_settings.html:4
|
||||
#: crochet/templates/crochet/account_settings.html:18
|
||||
#: crochet/templates/crochet/base.html:50
|
||||
#: crochet/templates/crochet/base.html:52
|
||||
msgid "Ajustes de la cuenta"
|
||||
msgstr ""
|
||||
|
||||
@@ -84,21 +82,21 @@ msgid "Volver a mis patrones"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/base.html:39
|
||||
msgid "Idioma"
|
||||
msgid "Cambiar idioma"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/base.html:54
|
||||
#: crochet/templates/crochet/base.html:56
|
||||
msgid "Cerrar sesión"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/base.html:60
|
||||
#: crochet/templates/crochet/base.html:62
|
||||
#: crochet/templates/crochet/home.html:24
|
||||
#: crochet/templates/registration/login.html:4
|
||||
#: crochet/templates/registration/login.html:14
|
||||
msgid "Iniciar sesión"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/base.html:61
|
||||
#: crochet/templates/crochet/base.html:63
|
||||
#: crochet/templates/registration/register.html:29
|
||||
msgid "Registrarme"
|
||||
msgstr ""
|
||||
@@ -163,12 +161,12 @@ msgstr ""
|
||||
msgid "Guardar"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:34
|
||||
msgid "Exportar a PDF"
|
||||
#: crochet/templates/crochet/pattern.html:33
|
||||
msgid "Ver patrón"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:38
|
||||
msgid "Eliminar patrón"
|
||||
#: crochet/templates/crochet/pattern.html:34
|
||||
msgid "Exportar a PDF"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:45
|
||||
@@ -282,11 +280,6 @@ msgstr ""
|
||||
msgid "Secciones"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:143
|
||||
#: crochet/templates/crochet/pattern.html:189
|
||||
msgid "Vista previa"
|
||||
msgstr ""
|
||||
|
||||
#: crochet/templates/crochet/pattern.html:152
|
||||
msgid "Colapsar todo"
|
||||
msgstr ""
|
||||
|
||||
@@ -22,23 +22,26 @@
|
||||
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{% for pattern in patterns %}
|
||||
<div class="card bg-base-100 shadow border border-base-300">
|
||||
<figure class="h-40 bg-base-200">
|
||||
{% if pattern.cover_image_thumbnail %}
|
||||
<img src="{{ pattern.cover_image_thumbnail.url }}" alt="" class="w-full h-full object-cover">
|
||||
{% else %}
|
||||
<span class="text-4xl">🧶</span>
|
||||
{% endif %}
|
||||
</figure>
|
||||
<a href="{% url 'crochet:pattern_edit' pattern.uuid %}">
|
||||
<figure class="h-40 bg-base-200">
|
||||
{% if pattern.cover_image_thumbnail %}
|
||||
<img src="{{ pattern.cover_image_thumbnail.url }}" alt="" class="w-full h-full object-cover">
|
||||
{% else %}
|
||||
<span class="text-4xl">🧶</span>
|
||||
{% endif %}
|
||||
</figure>
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-lg">
|
||||
{% if pattern.page_settings.title %}{{ pattern.page_settings.title }}{% else %}{% trans 'Patrón sin título' %}{% endif %}
|
||||
</h2>
|
||||
<a href="{% url 'crochet:pattern_edit' pattern.uuid %}">
|
||||
<h2 class="card-title text-lg">
|
||||
{% if pattern.page_settings.title %}{{ pattern.page_settings.title }}{% else %}{% trans 'Patrón sin título' %}{% endif %}
|
||||
</h2>
|
||||
</a>
|
||||
<p class="text-sm text-base-content/60">
|
||||
{% blocktrans with date=pattern.updated_at|date:'d/m/Y' %}Actualizado el {{ date }}{% endblocktrans %}
|
||||
</p>
|
||||
<div class="card-actions justify-end mt-2">
|
||||
<a href="{% url 'crochet:pattern_detail' pattern.uuid %}" class="btn btn-sm btn-outline">{% trans 'Ver patrón' %}</a>
|
||||
<a href="{% url 'crochet:pattern_edit' pattern.uuid %}" class="btn btn-sm btn-primary">{% trans 'Editar' %}</a>
|
||||
<a href="{% url 'crochet:pattern_detail' pattern.uuid %}" class="btn btn-sm btn-outline">{% trans 'Vista previa' %}</a>
|
||||
<form method="post" action="{% url 'crochet:pattern_delete' pattern.uuid %}"
|
||||
onsubmit="return confirm('{{ delete_confirm_message }}')">
|
||||
{% csrf_token %}
|
||||
|
||||
@@ -27,20 +27,22 @@
|
||||
<a href="{% url 'crochet:home' %}" class="btn btn-ghost text-xl px-2">🧶 Crochet</a>
|
||||
</div>
|
||||
<div class="flex-none flex items-center gap-2">
|
||||
<!-- Cambia de idioma sin perder la página en la que estás: cada
|
||||
ruta traducible (ver crochet/urls.py) cambia entera de un
|
||||
idioma a otro, no solo el prefijo (/es/, /en/), así que no
|
||||
basta con sustituirlo a mano en request.path (ver
|
||||
crochet_i18n.translate_url). onchange en vez de un <form> normal
|
||||
porque cada <option> lleva ya la URL completa de destino (no
|
||||
hay un único action al que enviar un valor). -->
|
||||
{% get_current_language as CURRENT_LANGUAGE %}
|
||||
{% get_available_languages as AVAILABLE_LANGUAGES %}
|
||||
<select class="select select-sm select-bordered" onchange="window.location.href=this.value" aria-label="{% trans 'Idioma' %}">
|
||||
{% for lang_code, lang_name in AVAILABLE_LANGUAGES %}
|
||||
<option value="{% translate_url request.path lang_code %}"{% if lang_code == CURRENT_LANGUAGE %} selected{% endif %}>{{ lang_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- El idioma es una preferencia de la página, no de la cuenta: va
|
||||
siempre en el mismo sitio del navbar, tanto si has iniciado
|
||||
sesión como si no, en vez de vivir dentro del dropdown de
|
||||
usuario (que no existe para anónimos). Cada opción es un <a>
|
||||
normal (no un <select>), así que navegar con teclado entre
|
||||
ellas no dispara nada hasta que se pulsa/activa una. -->
|
||||
<div class="dropdown dropdown-end">
|
||||
<button type="button" tabindex="0" class="btn btn-sm btn-ghost" aria-label="{% trans 'Cambiar idioma' %}">{{ CURRENT_LANGUAGE|language_flag }} {{ CURRENT_LANGUAGE|upper }}</button>
|
||||
<ul tabindex="0" class="dropdown-content menu menu-sm bg-base-100 border border-base-300 rounded-box z-10 w-40 p-2 shadow">
|
||||
{% for lang_code, lang_name in AVAILABLE_LANGUAGES %}
|
||||
<li><a href="{% translate_url request.path lang_code %}"{% if lang_code == CURRENT_LANGUAGE %} class="menu-active"{% endif %}>{{ lang_code|language_flag }} {{ lang_name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% if user.is_authenticated %}
|
||||
<!-- Dropdown CSS puro de daisyUI (sin JS propio): se abre con
|
||||
:focus-within al pulsar/tabular al botón disparador. -->
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<form method="post" action="{% url 'crochet:pattern_delete' pattern.uuid %}"
|
||||
onsubmit="return confirm('{{ delete_confirm_message }}')">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-outline btn-error">{% trans 'Eliminar patrón' %}</button>
|
||||
<button type="submit" class="btn btn-sm btn-outline btn-error">{% trans 'Eliminar' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -3,6 +3,12 @@ from django.urls import translate_url as django_translate_url
|
||||
|
||||
register = template.Library()
|
||||
|
||||
# Mismos idiomas que LANGUAGES en config/settings/base.py.
|
||||
LANGUAGE_FLAGS = {
|
||||
'es': '🇪🇸',
|
||||
'en': '🇬🇧',
|
||||
}
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def translate_url(path, lang_code):
|
||||
@@ -13,3 +19,8 @@ def translate_url(path, lang_code):
|
||||
# prefijo (p.ej. /es/patron/<uuid>/editar/ frente a
|
||||
# /en/pattern/<uuid>/edit/).
|
||||
return django_translate_url(path, lang_code)
|
||||
|
||||
|
||||
@register.filter
|
||||
def language_flag(lang_code):
|
||||
return LANGUAGE_FLAGS.get(lang_code, '')
|
||||
|
||||
@@ -56,7 +56,7 @@ class HomeViewTests(TestCase):
|
||||
class LanguageSwitcherTests(TestCase):
|
||||
def test_home_page_switcher_offers_the_same_page_in_english(self):
|
||||
response = self.client.get('/es/')
|
||||
self.assertContains(response, '<option value="/en/"')
|
||||
self.assertContains(response, 'href="/en/"')
|
||||
|
||||
def test_translated_route_switcher_preserves_the_current_view(self):
|
||||
# No solo cambia el prefijo (/es/ -> /en/): toda la ruta traducible
|
||||
@@ -71,12 +71,28 @@ class LanguageSwitcherTests(TestCase):
|
||||
|
||||
response = self.client.get(es_url)
|
||||
|
||||
self.assertContains(response, f'value="{en_url}"')
|
||||
self.assertContains(response, f'href="{en_url}"')
|
||||
|
||||
def test_current_language_is_preselected(self):
|
||||
def test_current_language_is_shown_on_the_trigger_button(self):
|
||||
response = self.client.get('/es/')
|
||||
self.assertContains(response, '<option value="/es/" selected>')
|
||||
self.assertContains(response, '<option value="/en/">')
|
||||
self.assertContains(response, '🇪🇸 ES<')
|
||||
|
||||
def test_menu_options_show_a_flag_per_language(self):
|
||||
response = self.client.get('/es/')
|
||||
|
||||
self.assertContains(response, '🇪🇸 Español')
|
||||
self.assertContains(response, '🇬🇧 Inglés')
|
||||
|
||||
def test_switcher_is_shown_regardless_of_login_state(self):
|
||||
# El idioma es una preferencia de la página, no de la cuenta: debe
|
||||
# verse tanto si hay sesión iniciada como si no, no solo dentro del
|
||||
# dropdown de usuario (que no existe para anónimos).
|
||||
user = User.objects.create_user(username='crocheter', password='a-very-uncommon-pw-1')
|
||||
self.client.force_login(user)
|
||||
|
||||
response = self.client.get('/es/')
|
||||
|
||||
self.assertContains(response, '🇪🇸 ES<')
|
||||
|
||||
|
||||
class NavbarAccountDropdownTests(TestCase):
|
||||
@@ -94,10 +110,24 @@ class NavbarAccountDropdownTests(TestCase):
|
||||
self.assertContains(response, f'href="{settings_url}"')
|
||||
self.assertContains(response, f'action="{logout_url}"')
|
||||
|
||||
def test_anonymous_user_does_not_see_the_dropdown(self):
|
||||
def test_anonymous_user_does_not_see_the_account_dropdown(self):
|
||||
with translation.override('es'):
|
||||
settings_url = reverse('crochet:account_settings')
|
||||
|
||||
response = self.client.get('/es/')
|
||||
|
||||
self.assertNotContains(response, 'dropdown dropdown-end')
|
||||
# El dropdown de idioma sí está presente para anónimos; lo que no
|
||||
# debe verse es el de la cuenta (ajustes/cerrar sesión).
|
||||
self.assertNotContains(response, f'href="{settings_url}"')
|
||||
self.assertEqual(response.content.decode().count('class="dropdown dropdown-end"'), 1)
|
||||
|
||||
def test_language_dropdown_is_separate_from_the_account_dropdown(self):
|
||||
user = User.objects.create_user(username='crocheter', password='a-very-uncommon-pw-1')
|
||||
self.client.force_login(user)
|
||||
|
||||
response = self.client.get('/es/')
|
||||
|
||||
self.assertEqual(response.content.decode().count('class="dropdown dropdown-end"'), 2)
|
||||
|
||||
|
||||
class PatternEditViewTests(TestCase):
|
||||
|
||||
Reference in New Issue
Block a user