Migrating legacy data to your Django project by Adolfo Fitoria
Published October 25, 2019
This video features Adolfo Fitoria at DjangoCon US 2021 in Online.
All 2021 talks have English and Spanish captions.
En esta charla hablaremos sobre cómo preparar tu proyecto para soportar múltiples idiomas en nuestros datos estáticos (plantillas, mensajes, nombres de campos y modelos) selección automática o manual de idioma, traducción de URLs y traducción de contenido.
This talk was presented at: https://2021.djangocon.us/talks/se-habla-espanol-django-y-multiples/
LINKS:
Follow Adolfo Fitoria 👇
On Twitter: https://twitter.com/Fitoria
On GitHub: https://github.com/fitoria
Website: http://fitoria.net
Follow DjangCon US 👇
https://twitter.com/djangocon
Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/
Video production by the speaker and DjangoCon US 2021 Volunteers.
Django includes built-in support for internationalization (I18N) and localization (L10N), allowing developers to translate application strings, templates, URLs, and formats such as dates and numbers. Adolfo Fitoria explains the workflow: mark strings with `gettext`/`gettext_lazy`, generate and translate `.po` files, compile them into `.mo` files, configure language settings and `LocaleMiddleware`, and offer users a language selector. For database content, he recommends `django-parler`, which stores translated fields in a related table and integrates with the Django admin; he also stresses that multilingual support is easier to design from the beginning than to retrofit later.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Hola a todos, bienvenidos a mi charla de sitios multidiomas con Django. Soy Adolfo Victoria, originario de Manego, Nicaragua y espero que sea de su agrado y poder compartir con ustedes todo mi conocimiento sobre este tema. Vamos a hablar un poco de traducción del contenido y de nuestras aplicaciones en Django. internacionalización localización que son esos la internacionalización es el proceso por el cual nosotros traducimos de un idioma hacia otro nuestras aplicaciones. Por ejemplo, traducimos las cadenas de amigo, friend, frumos, según el tipo de idioma. La localización es donde nosotros traducimos dentro de un idioma y otro y además dentro a veces del mismo idioma según la ubicación geográfica.
distintos formatos de fecha, formatos de separación de miles, formatos de separación de decimales, entre otras cosas. además de adaptar nuestras aplicaciones hacia la cultura donde vamos a funcionar Estos términos son abribados de dos maneras, I18N y L10N. ¿Por qué son sus números? Sos números son la cantidad de letras que tienen dentro de la primera letra con la última. En este caso la internacionalización en inglés. Tiene 18 letras en medio, la I y la N. y la localización tienen 10 letras entre la L
y la N. Por eso es que ustedes van a ver mucho en todo este tipo de documentación estos términos intercambiados y cuando yo me di cuenta de qué significaba al final I18N y L10N, me escuto la cabeza, pero pensaba que era alguna otra razón. Django, ese framework con baterÃas incluidas, ya trae por defecto soporte para la traducción de nuestras aplicaciones. Dentro de esto está el módulo i18n, donde están las funciones getText, getTextLazy , n getText en el text lazy entre otras también tenemos en nuestros settings podemos activar estas funcionalidades usando el use
l10n y el use l10 i18n para activar estas funciones también tenemos funcionalidad para traducir nuestras plantillas de html y para hacer todo el workflow de crear una cadena de traducción traducirla compilarla y usarla en el programa primer paso vamos preparar nuestro proyecto primero Vamos a poner el lenguaje base de nuestro proyecto. En esto se logra con el Setting Language Code, que ahà ponemos nuestro lenguaje que va a ser el principal. en mi caso pongo es young ni que es español y dentro de esto ponemos también por defecto de bien
activo pero nos aceramos que estemos usando idone y ldn igual true y en locales pad agregamos un directorio en la base de proyecto donde este directorio va a guardar todas las cadenas de traducción que tengamos en nuestras plantillas y en otros archivos en este ejemplo vamos a ver una aplicación bastante sencilla de blog en la cual hay un solo modelo que tiene tres campos el tÃtulo el cuerpo y la fecha Django trata de adivinar por convención varias cosas primero asume que el nombre de los campos
va a ser el nombre el nombre del campo que especificamos va a ser el nombre que va a usar en las etiquetas en la administración en el formulario etcétera Todos los plurales le voy a agregar una S final o voy a usar las reglas del inglés para pluralizar. Va a capitalizar las palabras, esto significa que va a poner la primera letra de cada palabra en mayúscula. Y va a asumir que los guiones bajos de los campos son espacios en blanco. Para preparar nuestro modelo, como anteriormente lo habÃamos visto, tenemos que primero importar la función getTextlacy como guión bajo. ¿Por qué se usa de esta manera? Es una convención que se ha llegado para que
no tenemos que escribir Get TextLazy por cada cadena que vamos a marcar para traducir. sino que se usa el alias del guión bajo para que sea más corto y además que es algo que por convención se ha usado anteriormente en otros proyectos primero vamos a marcar cada uno de nuestros campos con su label correcto el primer campo de los modelos de los campos de bases de datos de Django siempre es el label Y aquà ponemos guión bajo, abre paréntesis para invocar la función getText y ponemos la cadena que queremos que traduzca por defecto. si se fijan bien en este campo yo he puesto title con t mayúscula
body con b mayúscula y publication date con P mayúsculas porque al especificar el label lo va a tomar literalmente no va a hacer ninguna de estas capitalizaciones ni ninguna de estas convenciones que hemos hablado anteriormente Entonces tenemos que iniciar bien y ponerlo con mayúscula porque asà va a salir. Luego también traducimos el nombre del modelo propio. usando la clase meta, la opción de clase meta. Usamos el verbos name y el verbos name plural. Y asà especificamos el nombre post y post con ese plural para marcarlo para traducir. La función GetTextLazy lo que hace al final es marcar una cadena y decirle
a nuestro proyecto que esta cadena va a ser traducida según el idioma que se requiera. Ya viéndolo en el álbum van a ver que va a salir en español ciertas cosas, pero en inglés otras cosas. Por ejemplo, ven la palabra añadir. pero no vemos ni title ni body ni publication date traducido pero que porque ha pasado esto porque no hemos generado todavÃa nuestro archivo de traducción Para esto vamos a hacer dos pasos primero. Primeramente vamos a crear el director local que hemos especificado en settings y dentro de nuestra aplicación vamos a crear también un director local. Dentro del directorio local de la aplicación se guardan las cadenas que hemos marcado dentro del espacio de la aplicación misma, mientras que en el directorio general de nuestro proyecto se van a guardar las cadenas
que no están dentro de la aplicación pero que quizás están en las plantillas o están a un nivel afuera de toda la aplicación luego de esto vamos a correr el comando make messages con la bandera guión l para especificarle el idioma que vamos a traducir como nosotros queremos pasar de inglés a español especificamos guión l es Si quisiéramos otro idioma, pondrÃamos el código corto de dos letras para el idioma destino. Esto va a generar. un archivo punto po dentro de cada carpeta local dentro de cada carpeta local le voy a poner el código idioma otra carpeta que se llama lsmessages
y dentro de esta carpeta Django. po estos archivos son a base de texto plano y se ven de esta manera como está aquà a la izquierda especifica un comentario donde fue encontrado este archivo en este caso blog models. pÃas 6 78 etc primero es message id que es la cadena que está marcada dentro de ese archivo y luego message string que es lo que nosotros vamos a traducir transformemos lo que vemos a la izquierda a lo que vemos a la derecha donde ya podemos ver que está traducido title a tÃtulo body a cuerpo
etc Para traducir este tipo de archivos. po podemos usar otras herramientas además de nuestro director de texto favorito. está peedit está pudol está peo d editor y transistex peodit es una aplicación de escritorio que está bien para uso local pero si nosotros tenemos un proyecto muy grande donde van muchos idiomas y necesitamos un equipo de traducción recomendarÃa usar transifacts o feo editor que son aplicaciones web para de manera colaborativa editar los archivos. po luego los archivos. po se tienen que compilar y generar archivos.
mo que son un formato binario donde es lo que lee la utilidad de getText para mostrar nuestra aplicación los archivos meo se generan a partir de los peos y el servidor debe reiniciarse cada vez para ver los cambios si nosotros generamos archivo y no reiniciamos el servidor no vamos a a mostrar las cadenas actualizadas esto es vitalmente importante en producción especialmente y usamos el comando python manage compile messages para todos los archivos. po de nuestro proyecto convertirlos a mo Luego de este proceso nos va a quedar este tipo de estructura
directorio donde al lado del punto PO está el punto MO. Y ahora al recargar nuestro proyecto si vemos las traducciones que hemos especificado en archivo. po, tÃtulo se convierte a tÃtulo, body se convierte a cuerpo, etc. y hasta ahà estamos muy bien ahora queremos traducir nuestras plantillas nuestras plantillas tiene un proceso un poquito diferente primeramente tenemos que importar la biblioteca de 18 en las plantillas y podemos usar la función translate para marcar una cadena de traducción que serÃa el equivalente a usar el guión bajo paréntesis para
marcar una cadena de nuestros modelos tenemos también el blocks translate que es para marcar un bloque de texto que sea más grande y que tenga quizá dentro variables y podemos usar ese y también tenemos otra función como por ejemplo getCurrentLanguage que serÃa obtener cuál es el lenguaje que está activo en el en el proyecto y asà podemos mostrar que se lleva una banderita o mostrar un selector de idioma y por último otra función importante ahà es language que es una función que dentro del bloque de texto de la plantilla este bloque acá va a estar siempre traducido al idioma que hemos especificado en el parámetro del
de la función en este caso lo que pongamos aquà en en este ejemplo en texto acá va a ser siempre en inglés sin importar que el usuario haya seleccionado otro idioma para el resto en nuestro proyecto tenemos una plata bastante sencilla donde simplemente tenemos un bloque de tÃtulos un h1 para el tÃtulo de nuestra página y luego de esto un leer más que va hacia el absolute url este archivo de plantilla lo convertirÃamos a traducir con este ejemplo primeramente que acá como habÃa mencionado antes el i18n
luego de esto cada cadena que nosotros deseamos traducir se va a convertir a translate y la cadena que queremos marcar y luego de eso tendrÃamos que generar de vuelta al archivo. peo traducirlo generar el vmeo y revisar Entonces el resultado va a ser de esta manera. Aquà a la izquierda van a ver el idioma original. Y a la derecha el idioma traducido donde está en español y el izquierdo en inglés. La única diferencia es que el tÃtulo del sitio está en el idioma correspondiente y el link de leer más.
está traducido. Si vienen viendo el contenido de la entrada, que serÃa el tÃtulo y el body, el tÃtulo y el cuerpo, no está traducido todavÃa y eso es algo que veremos más adelante en la charla. Block Translate también tiene otra función importante, que podemos pluralizar cadenas. ¿Qué nos referimos con plurializar? Por ejemplo, si tenemos un conteo de post en nuestro blog, decir tengo 10 entradas con ese final pero si yo tuviese una tendrÃa que decir 10 una entrada sin s Esto es lo que hace la pluralización. Podemos marcar una cadena y brindar alternativa singular y alternativa plural.
Block Strandling tiene esta opción en el parámetro count, donde especificamos que va a haber un contenedor de un elemento para poder hacer la propia programación. En este ejemplo yo he usado también el parámetro stream para que no agregue espacios en blanco y el parámetro context para mandarle al traductor un contexto de lo que se está traduciendo. Esto es importante porque A veces hay palabras que pueden tener distintos significados en un contexto. Por ejemplo, el mes mayo en inglés puede significar. un mes es me puede ser un nombre me y puede ser un verbo me también entonces según el contexto A veces cuando tenemos el punto PO
y no sabemos dónde está esa cadena y qué es lo que está haciendo, es muy difÃcil saber cómo traducirlo. porque si lo ponemos en inglés ejemplo mayo puede ser mey puede ser mayo mayo puede ser puedo o mayo puede ser un nombre que en este caso serÃa igual me y es complicado hacer algo. Para eso tenemos la opción context donde pasamos una cadena que se da como comentario en el archivo. po. Al generar archivo. po tenemos El primer lÃnea serÃa el message context donde está el entry count, que es el mensaje que nosotros pusimos y especificamos en el template. luego de eso tendrÃamos el message id que es el singular
y el message id en plural que nos dice cuál cuál es la dos caras y tenemos que traducirlo de esta manera donde tenemos meses string 0 meses string 1 donde está el singular y el plural y luego tenemos este ejemplo es lo que nos produce cuando tenemos una sola entrada y cuando tenemos dos entradas y tener un contexto bueno para que sea correcto y sea lo más significativo para el proyecto de usuario. Detección de idioma mediante el middleword. Una cosa que nosotros normalmente queremos con proyectos de traducción es que detectemos automáticamente el idioma que el usuario
pueda requerir esto se logra en Django activando el middleware de local middleware una cosa importante para activarlo es agregarlo justo después de session meterware y antes de common meterware porque estos tienen dependencia entre ellos si lo agregamos en otro orden puede hacer que se generen algún fallo Lo que hace este middleware es que detecta por un algoritmo bastante simple. Primero va a revisar si en la sesión tenemos activo un idioma. si tenemos la cookie del lenguaje activada en nuestro navegador por último va a detectar también
si hay un patrón de código de idioma en las urls y por último va a detectar con la cabecera accept language que los navegadores mandan según la configuración de los usuarios en su en su dispositivo para que también esté mirror funcione tenemos que especificar cuáles son nuestros idiomas que soportamos en el proyecto. Esto se logra agregándolo al especificándolo en el setting languages. Por defecto el setting languages en Django trae todos los idiomas ya puestos y es una lista bastante grande. Entonces asà nosotros lo delimitamos usando esta sintaxis.
marcando las cadenas del nombre del idioma como traducir para traducir para que si nosotros lo mostramos en un selector salgan correctamente De esta manera podemos verlo acá. Hemos especificado el idioma inglés y el idioma español y eso es todo. Luego de eso, el local en Middleware se hace cargo del resto. Si él detecta las condiciones que les mencioné anteriormente, él va a activar la traducción. más pertinente que hemos que según lo que él detecta entonces con esta prueba que estamos viendo ahorita vemos una un navegador que entró con el asset language M
y un navegador que entró con el Asset Language S y él traduce según sea necesario Pasamos a la segunda etapa. Ya tenemos traducido nuestro proyecto y todas nuestras cadenas se ven espectaculares. Tenemos también activado local en Middleware donde va a detectar automáticamente que idioma el usuario requiere pero ahora vamos con la traducción de los contenidos y los datos esta parte no está soportada por defecto por el framework Porque cada uno lo puede hacer según sus capacidades. Además que los datos van a apoyar mucho de proyecto a proyecto. Hay bastantes paquetes disponibles para hacer esta parte, pero yo personalmente recomiendo Django
Parley, que es un paquete que es bastante completo, soporte a Ladmin y es bastante fácil de usar también. Esta parte puede ser un dolor de cabeza si nuestro proyecto ya existe y necesitamos transformarlo. Según el paquete que nosotros elijamos, el proceso de migración puede variar. y como son datos vas a tener que crear migración de datos por cada tipo de modelos que vamos a hacer Hay una charla en el Django con US del 2018 que se llama Data Internationalization en Django de Rafael Mitchell. y él explica además de otro este proyecto que he recomendado explica a más profundidad cómo funcionan estos proyectos y cuáles
sus beneficios y sus desventajas según sea Django Parler lo que hace es crear una tabla intermedia donde él guarda las traducciones según el idioma. Hace una relación foreign key con nuestra tabla principal y dentro de esta tabla intermedia lo que hace es guardar una a una las traducciones que hemos puesto. Para instalarlo vamos a hacer el proceso y agregamos parler a install apps. Luego de eso especificamos los lenguajes y las idiomas traducibles en parler languages. y luego de esto tenemos que transformar nuestro modelo nuestro modelo tendrÃa que heredar primeramente
de el modelo translatable model de parler y los campos que son traducibles en este caso el tÃtulo y el cuerpo van a ser declarados de esta manera como translations igual translated fields y dentro la lista de campos que nosotros queremos marcar como traducibles luego de eso nosotros generamos estas migraciones hacemos el proyecto y la parte del admin para que se vea mejor en vez de usar el model admin por defecto de Django usamos translatable admin department luego de admin de translibero admin tenemos todas las mismas opciones disponibles de
model admin asà que lo podemos usar con normalidad y ya en acción se ve de esta manera él va a agregar una tab por cada idioma que nosotros ponemos y asà el tÃtulo y el cuerpo va a estar traducidos según la cantidad de idiomas que hay. La fecha como un campo que no tiene idioma va a estar igual para todos. Entonces, de esta manera podemos traducir contenido de nuestras aplicaciones y habilitarlo en el admin para que las personas que van a subir el contenido puedan poner las diferentes versiones. Otras personas lo que hacen es que en los modelos
agregan un campo de idioma y meten dos filas o n cantidad de filas según el idioma. para traducir contenido pero esta para mà a mi parecer esta es la opción más amigable al usuario y además que tiene un buen rendimiento para traducir contenido en Django Luego, ya en la práctica, tenemos un sitio que está traducido tanto nuestras cadenas como el contenido en el idioma que hemos definido. y asà hemos completado como toda la parte de traducir las cadenas contenido ahora Traduciendo URLs. Es algo importante cuando traducimos URLs para mejorar el SEO, también para tener un mejor contexto al
usuario. Esto lo podemos lograr con el siguiente proceso. Primeramente vamos a marcar como cadena la URL que nosotros queremos traducir. Esto lo logramos con la función GetTextLazy, igual que en los modelos. Luego tenemos que en el root URL, o sea, en la URL. py principal de nuestro proyecto, vamos a incluir la función i18n patterns en vez de usar la lista simple de esta manera a Django le decimos que nuestras URLs van a tener un prefijo de idioma Lo que hace I18N es agregar el prefijo de idioma en los URLs y por ejemplo si nuestro usuario visita el sitio y habla español
pondrÃa S. pleca admin por ejemplo y si habla inglés serÃa pleca en pleca admin o el patrón que nosotros hayamos definido aplicamos también el proceso de generar punto po y generar los puntos m o y esto nos logra traducir las URL dentro del proyecto de manera que juegue junto con el local de Miniware y él se encargue de redigirte al lugar correcto Si queremos ofrecer a nuestros usuarios el cambio de idioma, porque puede ser que el usuario esté usando y te detecte que está en inglés, pero quieres leer en español, Django también te tiene cubierto.
puedes usar este patrón que se llama i18n y él va a incluir una serie de funciones que te ayudan a mandar a cambiar el idioma y activar otro idioma en nuestra aplicación En nuestra plantilla vamos a incluir este bloque de texto. Aquà nos podemos ver creativos poniendo banderas, poniendo enlaces. o según la manera que nosotros queramos, pero este es el ejemplo que está directamente en la documentación de Django sin hacerle ningún cambio, lo que genera este código Es un formulario pequeño donde la VL de Z Language, que es la que viene del patrón I18N y es la que se encarga de hacer el cambio de idioma. Al final
esto se ve de esta manera. Se ve como un pequeño formulario drop-down donde nosotros podemos seleccionar el idioma que queremos. poner y activar y el sitio va a cambiar su idioma para este usuario y de esa manera tenemos una gran variedad de funciones primero funciones para traducir cadena luego traducir plantillas traducir contenido traducir la buena de LES y ofrecer para el usuario cambiar de idioma entre entre proyectos y con esto vamos cerrando ya en todo viene listo en bien listo para hacer proyectos multi idioma podemos ajustarnos según el
el flujo de trabajo que nosotros queramos podemos decir no no quiero traducir mis URLs solo quiero traducir las cadenas o no no quiero traducir cierta parte del sitio lo quiero mostrar asà esto es a su gusto es mucho más cómodo iniciar un proyecto que esté pensado para ser traducido que venir y agarrar un proyecto ya comenzado para traducir porque tendrÃamos que ir buscando las cadenas, marcarlas como traducción y traducirlas. Además que la parte del contenido, como les he explicado antes, pues va a ser un dolorcito de cabeza venir y mirar los datos a un modelo de multiidioma. Y la traducción del contenido va a depender de tu caso de uso. Ahà va a depender si necesitas
duplicar contenido, como les hablé, o usar alguna de estas aplicaciones para que se puedan traducir los datos. de manera integrada cualquier pregunta o duda me pueden escribir este es mi correo me pueden seguir en twitter twitter está ahà y tengo un blog un poco de cuidado pero ahà está para que me puedan contactar Esto serÃa todo, espero les haya gustado y cualquier cosa pueden escribir. Saludos.
Internationalization (I18N) prepares an application to translate its text, while localization (L10N) adapts it to a language, region, culture, and conventions such as dates and number formatting.
Discussed at 0:32Import Django’s lazy translation function, conventionally as `_`, and wrap field labels and the model’s `verbose_name` and `verbose_name_plural` in it. Explicit labels are used literally, so capitalization must be supplied as desired.
Discussed at 5:16Create the locale directories, run `makemessages -l <language>` to generate `.po` files, edit their translations, and run `python manage.py compilemessages` to produce `.mo` files. Restart the server after compiling so the updated translations are loaded.
Discussed at 7:46Load Django’s internationalization template library and mark strings with `{% translate %}`; use `{% blocktranslate %}` for larger blocks or text containing variables. Afterward, regenerate, translate, and compile the message files.
Discussed at 10:52`blocktranslate` can use a `count` parameter to select singular or plural forms. A context value adds clarification for translators when the same source word can have different meanings.
Discussed at 13:53Enable `LocaleMiddleware` after `SessionMiddleware` and before `CommonMiddleware`, then define the supported languages in `LANGUAGES`. Django checks the session, language cookie, URL language prefix, and finally the browser’s `Accept-Language` header.
Discussed at 17:03Django does not translate stored content by default; the speaker recommends Django Parler. It stores translations in an intermediate table, and translatable models define translated fields while the admin provides a tab for each language.
Discussed at 20:08Mark URL patterns for translation and use `i18n_patterns` in the project’s root URL configuration, which adds a language prefix such as `/es/` or `/en/`. Generate and compile the message files afterward so the localized URL patterns are available.
Discussed at 23:04Use Django’s `set_language` mechanism from the `i18n` URL pattern and add the documented language-selection form to a template. The form can be styled as a dropdown, flag selector, or another interface that submits the chosen language.
Discussed at 25:39Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026