Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions doc/traducciones.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Guía rápida sobre traducciones

> [!IMPORTANT]\
> La documentación oficial está disponible [aquí](https://docs.djangoproject.com/en/5.2/topics/i18n/translation/).\
> Personalmente recomiendo leer al menos hasta la sección de `Lazy Translation` (incluida).

> [!IMPORTANT]\
> No queremos traducciones hechas por IA.
> Valoramos el trabajo humano y preferimos no disponer de las traducciones de un idioma antes que servir traducciones
> hechas por IA.\
> **Por favor, abstente de realizar contribuciones que no sean de autoría humana.**

## Procedimiento de traducción

### Modificación del código o las plantillas para integrar las traducciones

(Solo necesario la primera vez que se traduce un archivo)

#### En Python

Se introduce el texto a traducir en la llamada a la función `_()`, definida de forma distinta en función de qué archivo
se trate:

- En archivos habituales,\
`from django.utils.translation import gettext as _`.\
- En archivos ejecutados en el arranque de Django (`admin.py`, `settings.py`, `models.py`, etc.)
https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#lazy-translation \
`from django.utils.translation import gettext_lazy as _`
- En casos en los que el texto a traducir requiera contexto (aparece en varias situaciones con traducciones distintas),
emplear las variantes:\
https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#contextual-markers \
`from django.utils.translation import pgettext as _` y\
`from django.utils.translation import pgettext_lazy as _`\
como `_("<contexto>", "<texto a traducir>")`
- En traducciones que requieran plurales, usar las variantes:\
https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#pluralization \
`from django.utils.translation import ngettext` y\
`from django.utils.translation import ngettext`.
Para más detalles de su uso ver la documentación oficial.

Para aportar contexto adicional a los traductores, se debe añadir un comentario en la línea previa a la llamada con la
estructura siguiente:
`# Translators: <el comentario>`

Un ejemplo del uso está disponible en el archivo [settings.py](hackackathon/settings.py) en la definición de la variable `LANGUAGES`.

#### En plantillas

Se introduce el texto a traducir entre las comillas de `{% translate '' %}`.

Para aportar contexto adicional a los traductores, se debe añadir un comentario en la línea previa a la llamada con la
estructura siguiente:
`{# Translators: <el comentario> #}`

Un ejemplo del uso está disponible en el archivo [registro.html](templates/registro.html), en todos los textos presentes.

### Creación del archivo de traducción

`python manage.py makemessages --all`

### Traducción de los archivos generados

Se deberán traducir los archivos presentes en `locale/*/*.po`.

### Compilación de las traducciones para su uso

`python manage.py compilemessages`

> Esto es solo un resumen rápido.
> Para información detallada *recomiendo muy encarecidamente* leer la documentación oficial.
> Hay muchos matices que no están recogidos en este documento, bien por desconocimiento, bien por no extenderse en
> exceso.
6 changes: 3 additions & 3 deletions gestion/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
ParticipanteForm,
PaseForm,
Registro,
RevisarParticipanteForm,
RevisarMentorForm,
RevisarParticipanteForm,
)
from gestion.models import (
Mentor,
Expand Down Expand Up @@ -55,7 +55,7 @@ def registro(request: HttpRequest):
logger.debug("Intento de acceso con el registro cerrado")
return render(request, "registro_cerrado.html")

titulo = "Regístrate en"
titulo = _("Regístrate en")
url = reverse("registro")

if request.method == "GET":
Expand Down Expand Up @@ -130,7 +130,7 @@ def registro_mentores(request: HttpRequest):
logger.debug("Intento de acceso con el registro cerrado")
return render(request, "registro_cerrado.html")

titulo = "Registro de mentores"
titulo = _("Registro de mentores")
url = reverse("registro-mentores")

if request.method == "GET":
Expand Down
15 changes: 14 additions & 1 deletion hackackathon/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pathlib import Path
from zoneinfo import ZoneInfo

from django.utils.translation import gettext_lazy as _
from dotenv import load_dotenv

load_dotenv()
Expand Down Expand Up @@ -236,14 +237,26 @@
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/

LANGUAGE_CODE = "es-es"
LANGUAGE_CODE = "es"

TIME_ZONE = "Europe/Madrid"

USE_I18N = True

USE_TZ = True

# Translations
# https://docs.djangoproject.com/en/5.1/topics/i18n/translation/
# ./manage.py makemessages --all
# ./manage.py compilemessages
LANGUAGES = [
("es", _("Castellano")),
("gl", _("Gallego")),
("en", _("Inglés")),
]
LANGUAGE_COOKIE_NAME = "lang"
LOCALE_PATHS = (BASE_DIR / "locale",)


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
Expand Down
3 changes: 3 additions & 0 deletions hackackathon/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
from django.contrib import admin
from django.urls import include, path

from hackackathon import views

admin.site.site_header = "Hackackathon Admin"

urlpatterns = [
path("admin/", admin.site.urls),
path("idioma/<codigo>", views.idioma, name="idioma"),
path("", include("gestion.urls")),
]

Expand Down
29 changes: 29 additions & 0 deletions hackackathon/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (C) 2025-now p.fernandezf <p@fernandezf.es> & iago.rivas <delthia@delthia.com>

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_not_required
from django.http import HttpRequest
from django.shortcuts import redirect
from django.utils import translation
from django.utils.translation import gettext_lazy as _


@login_not_required
def idioma(request: HttpRequest, codigo: str):
idiomas_validos = [codigo for codigo, nombre in settings.LANGUAGES]

if codigo in idiomas_validos:
translation.activate(codigo)
else:
messages.error(
request,
_("Código de idioma no válido. Los posibles son")
+ ": "
+ ", ".join(idiomas_validos),
)

if siguiente := request.GET.get("next"):
return redirect(siguiente)

return redirect("registro")
Binary file added locale/en/LC_MESSAGES/django.mo
Binary file not shown.
93 changes: 93 additions & 0 deletions locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Hackackathon English translations
# Copyright (C) 2025-now p.fernandezf <p@fernandezf.es> & iago.rivas <delthia@delthia.com>
# This file is distributed under the same license as the Hackackathon package.
# p.fernandezf <p@fernandezf.es>, 2025.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Hackackathon VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-28 16:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: gestion/admin.py:47
#, python-format
msgid ""
"%d participante no tiene el correo verificado y no se ha podido aceptar."
msgid_plural ""
"%d participantes no tienen el correo verificado y no se han podido aceptar."
msgstr[0] ""
"%d participant's email wasn't verified and they couldn't be accepted."
msgstr[1] ""
"%d participants' emails weren't verified and they couldn't be accepted"

#: gestion/admin.py:59
#, python-format
msgid "%d participante ya estaba aceptado."
msgid_plural "%d participantes ya estaban aceptados."
msgstr[0] "%d participant was already accepted."
msgstr[1] "%d participants were already accepted."

#: gestion/admin.py:70
#, python-format
msgid "%d participante aceptado."
msgid_plural "%d participantes aceptados."
msgstr[0] "%d participant accepted."
msgstr[1] "%d participants accepted."

#: hackackathon/settings.py:253
msgid "Castellano"
msgstr "Spanish"

#: hackackathon/settings.py:254
msgid "Gallego"
msgstr "Galician"

#: hackackathon/settings.py:255
msgid "Inglés"
msgstr "English"

#: hackackathon/views.py:21
msgid "Código de idioma no válido. Los posibles son"
msgstr "Invalid language code. Valid ones are"

#: templates/registro.html:10
msgid "Regístrate en"
msgstr "Register at"

#. Translators: Etiqueta para la casilla de términos y condiciones
#: templates/registro.html:22
msgid "Acepto los"
msgstr "I accept the"

#: templates/registro.html:23
msgid "Términos y Condiciones"
msgstr "Terms and Conditions"

#: templates/registro.html:24
msgid "y el"
msgstr "and the"

#: templates/registro.html:25
msgid "Código de conducta"
msgstr "Code of conduct"

#: templates/registro.html:31
msgid "Apuntarme a HackUDC"
msgstr "Sign up for HackUDC"

#: templates/registro.html:36
msgid "Al enviar aceptas la"
msgstr "By signing up you accept the"

#: templates/registro.html:36
msgid "política de privacidad"
msgstr "privacy policy"
Binary file added locale/gl/LC_MESSAGES/django.mo
Binary file not shown.
92 changes: 92 additions & 0 deletions locale/gl/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Traducións de Hackackathonao galego
# Copyright (C) 2025-now p.fernandezf <p@fernandezf.es> & iago.rivas <delthia@delthia.com>
# Este arquivo distriúese baixo a mesma licenza que o paquete Hackackathon.
# p.fernandezf <p@fernandezf.es>, 2025.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Hackackathon VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-28 16:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: gestion/admin.py:47
#, python-format
msgid ""
"%d participante no tiene el correo verificado y no se ha podido aceptar."
msgid_plural ""
"%d participantes no tienen el correo verificado y no se han podido aceptar."
msgstr[0] "%d participante non ten o correo verificado e non se puido aceptar."
msgstr[1] ""
"%d participantes non teñen o correo verificado e non se puideron aceptar."

#: gestion/admin.py:59
#, python-format
msgid "%d participante ya estaba aceptado."
msgid_plural "%d participantes ya estaban aceptados."
msgstr[0] "%d participante xa estaba aceptado."
msgstr[1] "%d participantes xa estaban aceptados."

#: gestion/admin.py:70
#, python-format
msgid "%d participante aceptado."
msgid_plural "%d participantes aceptados."
msgstr[0] "%d participante aceptado."
msgstr[1] "%d participantes aceptados."

#: hackackathon/settings.py:253
msgid "Castellano"
msgstr "Castelán"

#: hackackathon/settings.py:254
msgid "Gallego"
msgstr "Galego"

#: hackackathon/settings.py:255
msgid "Inglés"
msgstr "Inglés"

#: hackackathon/views.py:21
msgid "Código de idioma no válido. Los posibles son"
msgstr "Código de idioma non válido. Os posibles son"

#: templates/registro.html:10
msgid "Regístrate en"
msgstr "Rexístrate en"

#. Translators: Etiqueta para la casilla de términos y condiciones
#: templates/registro.html:22
msgid "Acepto los"
msgstr "Acepto os"

#: templates/registro.html:23
msgid "Términos y Condiciones"
msgstr "Termos e Condicións"

#: templates/registro.html:24
msgid "y el"
msgstr "e o"

#: templates/registro.html:25
msgid "Código de conducta"
msgstr "Código de conducta"

#: templates/registro.html:31
msgid "Apuntarme a HackUDC"
msgstr "Apuntarme a HackUDC"

#: templates/registro.html:36
msgid "Al enviar aceptas la"
msgstr "Ao enviar aceptas a"

#: templates/registro.html:36
msgid "política de privacidad"
msgstr "política de privacidade"
Loading