Avete un'app Django che funziona in inglese. Ora dovete farla funzionare anche in altre lingue. Questa guida copre l'intero processo, dalla marcatura delle stringhe nel codice alla pubblicazione di un sito completamente localizzato, con esempi pratici a ogni passaggio.
Il framework di internazionalizzazzione di Django (comunemente chiamato i18n) e uno dei migliori disponibili. Gestisce le lingue da destra a sinistra, le regole di pluralizzazione, i formati delle date e tutte le altre cose che rendono la localizzazione davvero difficile. Il problema e che la configurazione coinvolge diverse parti in movimento, e la maggior parte dei tutorial ne copre solo una o due.
Cosa comporta realmente la localizzazione
La localizzazione non si limita alla traduzione delle stringhe. Un'app Django correttamente localizzata gestisce:
- Traduzione del testo (template, viste, modelli, JavaScript)
- Routing degli URL per lingua (
/en/about/,/de/about/) - Formattazione di date, orari e numeri (14/03/2026 vs 03/14/2026)
- Regole di pluralizzazione (l'inglese ha 2 forme, l'arabo ne ha 6, il giapponese ne ha 1)
- Layout da destra a sinistra per arabo, ebraico, farsi
- Gestione dei fusi orari
La maggior parte dei proggetti Django ha bisogno solo dei primi tre punti. Ma vale la pena sapere cosa puo fare il framework prima di iniziare, per non trovarsi in un vicolo cieco.
Passaggio 1: configurare le impostazioni
Iniziate con le impostazioni di internazionalizzazione in settings.py:
from django.utils.translation import gettext_lazy as _
LANGUAGE_CODE = "en"
USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = [
("en", _("English")),
("de", _("German")),
("fr", _("French")),
("ja", _("Japanese")),
("es", _("Spanish")),
]
LOCALE_PATHS = [
BASE_DIR / "locale",
]
LANGUAGES definisce quali lingue supporta il vostro sito. Includete solo le lingue che intendete effetivamente tradurre. Aggiungere 30 lingue qui senza tradurle crea solo file .po vuoti e confonde la strutura degli URL.
LOCALE_PATHS indica a Django dove cercare i file di traduzione. L'impostazione predefinita e una directory locale/ in ogni app, ma una singola directory locale/ a livello di progetto e piu facile da gestire.
Passaggio 2: aggiungere il middleware e la configurazione degli URL
Aggiungete il middleware per la localizzazione alla vostra impostazione MIDDLEWARE. L'ordine e importante:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware", # after SessionMiddleware
"django.middleware.common.CommonMiddleware",
# ...
]
LocaleMiddleware deve venire dopo SessionMiddleware (ha bisogno della sessione per ricordare le preferenze linguistiche) e prima di CommonMiddleware. Sbagliare questo ordine e una delle ragioni piu comuni per cui le traduzioni di Django falliscono silenziosamente.
Poi avvolgete i vostri pattern URL con i18n_patterns:
from django.conf.urls.i18n import i18n_patterns
urlpatterns = [
path("admin/", admin.site.urls),
]
urlpatterns += i18n_patterns(
path("", include("myapp.urls")),
)
Questo aggiunge un prefisso a tutti i vostri URL con il codice della lingua: /en/about/, /de/about/, /fr/about/. L'admin resta senza prefisso, dato che nella maggior parte dei progetti non necesita di localizzazione.
Passaggio 3: marcare le stringhe per la traduzione
Qui si concentra la maggior parte del lavoro. Ogni stringa rivolta all'utente nel codice deve essere racchiusa in una funzione di traduzzione.
Nel codice Python
from django.utils.translation import gettext as _
def my_view(request):
message = _("Your order has been placed.")
return render(request, "order.html", {"message": message})
Usate gettext (con alias _) nelle viste e nelle funzioni. Per le stringhe a livello di modulo, come le etichette dei campi dei modelli, usate gettext_lazy:
from django.utils.translation import gettext_lazy as _
class Product(models.Model):
name = models.CharField(_("product name"), max_length=200)
description = models.TextField(_("description"))
class Meta:
verbose_name = _("product")
verbose_name_plural = _("products")
La differenza e importante: gettext_lazy ritarda la ricerca della traduzione fino a quando la stringa viene effettivamente renderizzata, il che e necessario per tutto cio che viene valutato al momento dell'importazione (definizioni di modelli, campi di form, nomi di URL). Usare gettext normale a livello di modulo tradurra una sola volta all'avvio e servira la lingua sbagliata a tutti.
Nei template
{% load i18n %}
<h1>{% trans "Welcome to our store" %}</h1>
<p>
{% blocktrans count items=cart.item_count %}
You have {{ items }} item in your cart.
{% plural %}
You have {{ items }} items in your cart.
{% endblocktrans %}
</p>
{% trans %} gestisce le stringhe semplici. {% blocktrans %} gestisce le stringhe con variabili o pluralizzazione. Non dimenticate {% load i18n %} all'inizio di ogni template che usa questi tag.
In JavaScript
Django puo generare un catalogo JavaScript delle vostre traduzioni:
from django.views.i18n import JavaScriptCatalog
urlpatterns += i18n_patterns(
path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"),
)
Poi nel vostro JavaScript:
document.getElementById("status").textContent = gettext("Loading...");
Includete lo script del catalogo prima di qualsiasi JavaScript che usa gettext:
<script src="{% url 'javascript-catalog' %}"></script>
Passaggio 4: generare e tradurre i file .po
Una volta marcate le stringhe, generate i file di traduzione:
python manage.py makemessages -l de -l fr -l ja -l es
Questo crea i file .po nella vostra directory locale/:
locale/
de/LC_MESSAGES/django.po
fr/LC_MESSAGES/django.po
ja/LC_MESSAGES/django.po
es/LC_MESSAGES/django.po
Ogni file .po contiene voci come questa:
#: myapp/views.py:12
msgid "Your order has been placed."
msgstr ""
Il msgstr e dove va la traduzione. Potete compilare questi campi manualmente, assumere traduttori o automatizzare il processo con strumenti di traduzione basati sull'intelligenza artificiale.
Dopo la traduzione, compilate i file .po in file binari .mo che Django puo leggere in modo efficente:
python manage.py compilemessages
Eseguite compilemessages ogni volta che aggiornate le traduzioni. Dimenticare questo passaggio e un'altra ragione comune per cui le traduzioni non appaiono. Django legge i file .mo, non i file .po.
Passaggio 5: gestire la formattazione di date, numeri e orari
L'impostazione L10N di Django controlla come vengono formattate le date e i numeri. Con USE_L10N = True, Django usa automaticamnte la formattazione in base alla localizzazione:
{% load l10n %}
<p>Order date: {{ order.created_at }}</p>
<p>Total: {{ order.total }}</p>
Una data che appare come "July 10, 2026" in inglese verra automaticamente visualizzata come "10. Juli 2026" in tedesco e "2026年7月10日" in giapponese. I numeri seguono regole simili: 1,234.56 in inglese diventa 1.234,56 in tedesco.
Se dovete sovrascrivere il formato per valori specifici, usate i filtri localize e unlocalize:
{% load l10n %}
<!-- Always use locale formatting -->
<p>{{ value|localize }}</p>
<!-- Always use the default (English) format -->
<p>{{ value|unlocalize }}</p>
Passaggio 6: aggiungere un selettore di lingua
Gli utenti hanno bisogno di un modo per cambiare lingua. Ecco un semplice selettore di lingua che funziona con la vista set_language di Django:
{% load i18n %}
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<select name="language" onchange="this.form.submit()">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% for lang_code, lang_name in LANGUAGES %}
<option value="{{ lang_code }}"
{% if lang_code == LANGUAGE_CODE %}selected{% endif %}>
{{ lang_name }}
</option>
{% endfor %}
</select>
</form>
Assicuratevi che l'URL set_language sia incluso nella vostra configurazione degli URL:
urlpatterns = [
path("i18n/", include("django.conf.urls.i18n")),
# ...
]
Questo deve essere al di fuori di i18n_patterns, dato che il selettore di lingua stesso non ha bisogno di un prefisso linguistico.
Errori comuni e come evitarli
Usare gettext invece di gettext_lazy nei modelli
Questo e il bug di localizzazione piu comune nei progetti Django. I campi dei modelli, le etichette dei form e qualsiasi altra cosa definita a livello di modulo necessita di gettext_lazy, non di gettext. Il sintomo: tutti gli utenti vedono le traduzioni nella lingua con cui il processo del server e stato avviato.
Dimenticare di eseguire compilemessages
Avete modificato il file .po, riavviato il server, ma le traduzioni ancora non appaiono. Il file .mo e quello che Django legge, e non viene aggiornato automaticamnete. Aggiungete compilemessages alla vostra pipeline di distribuzione.
Ordine errato del middleware
LocaleMiddleware dopo CommonMiddleware significa che Django non puo rilevare la lingua dal prefisso dell'URL. La richiesta passa alla lingua predefinita ogni volta. Posizionatelo tra SessionMiddleware e CommonMiddleware.
Stringhe codificate direttamente nei template
E facile perdere stringhe che dovrebbero essere tradotte. Cercate nei vostri template il testo non racchiuso nei tag {% trans %} o {% blocktrans %}. I casi piu frequenti: etichette dei pulsanti, segnaposto dei campi dei form, messaggi di errore e testo del footer.
Non gestire la pluralizzazione
L'inglese ha due forme plurali (1 item, 2 items). Il russo ne ha tre. L'arabo ne ha sei. Se codificate "item(s)" direttamente invece di usare ngettext o {% blocktrans count %}, le vostre traduzioni risulteranno goffe o grammaticalmente errate nelle altre lingue.
Automatizzare il flusso di lavoro della traduzione
Tradurre manualmente i file .po funziona per progetti piccoli, ma non e scalabile. Un tipico progetto Django con 200 stringhe traducibili in 5 lingue significa 1.000 traduzioni da gestire. Ogni volta che aggiungete o modificate una stringa, dovete aggiornare tutte le lingue.
Il flusso di lavoro di solito si presenta cosi:
- Marcate le nuove stringhe con
_()o{% trans %} - Eseguite
makemessagesper estrarle - Traducete le nuove voci in ogni file
.po - Eseguite
compilemessages - Fate il commit di tutto
I passaggi 3 e 4 sono quelli in cui le cose rallentano. I traduttori umani aggiungono latenza e costi. Il copia-incolla manuale nei servizi di traduzione e tedioso e soggetto a errori, sopratutto quando dovete preservare i formati segnaposto di Django come %(name)s o {count}.
Gli strumenti di traduzione basati sull'intelligenza artificiale possono automatizzare il passaggio 3 mantenendo il passaggio 4 nella vostra pipeline CI/CD. Il compromesso e che le traduzioni generate dall'IA potrebbero necessitare di revisione per sfumature e terminologia, ma per la maggior parte delle stringhe dell'interfaccia la qualita e sufficente per essere pubblicate direttamente.
Testare la localizzazione
Prima della distribuzione, verificate che la vostra localizzazione funzioni correttamente:
# Generate messages for all configured languages
python manage.py makemessages -a
# Check for missing translations
python manage.py compilemessages
# Start the dev server and switch languages
python manage.py runserver
Cose da verificare:
- Passate tra tutte le lingue supportate usando il selettore di lingua
- Verificate che gli URL includano il prefisso di lingua coretto
- Controllate che le date e i numeri siano formattati correttamente per ogni localizzazione
- Cercate le stringhe non tradotte (appariranno in inglese)
- Testate le lingue da destra a sinistra se le supportate
- Verificate che la pluralizzazione funzioni corettamente (testate con 0, 1, 2 e 5+ elementi)
Considerate l'aggiunta di un controllo CI che fallisca se qualche file .po ha voci non tradotte o contrassegnate come fuzzy. Questo previene distribuzioni accidentali con traduzioni mancanti.
Struttura del progetto
Una configurazione di localizzazione ben organizzata si presenta cosi:
myproject/
locale/
de/LC_MESSAGES/django.po
fr/LC_MESSAGES/django.po
ja/LC_MESSAGES/django.po
es/LC_MESSAGES/django.po
myapp/
templates/
views.py
models.py
settings.py
urls.py
TRANSLATING.md
Il file TRANSLATING.md e opzionale ma utile. Documenta le vostre preferenze terminologiche, le linee guida sul tono e qualsiasi regola specifica per la traduzione del vostro progetto. Se utilizzate strumenti di traduzzione basati sull'IA che supportano file di contesto, possono leggere questo file e applicare le vostre preferenze automaticamente.
Cosa fare dopo
Se partite da zero:
- Aggiungete le impostazioni e il middleware dai passaggi 1 e 2
- Scegliete il vostro template piu importante e marcate le sue stringhe (passaggio 3)
- Generate i file
.poper una sola lingua prima (passaggio 4) - Traducete quella lingua e verificate che funzioni dall'inizio alla fine
- Poi espandetevi a piu template e lingue
Se avete gia un'app parzialmente localizzata:
- Eseguite
makemessages -aper rigenerare tutti i file.po - Controllate le stringhe fuzzy o non tradotte
- Compilate le traduzioni mancanti
- Configurate un controllo CI in modo che le nuove stringhe non tradotte vengano rilevate prima di raggiungere la produzzione
Iniziare in piccolo ed espandersi e meglio che cercare di localizzare tutto in una volta. Fate funzionare completamente una lingua, poi aggiungetene altre.