# Django 6.0.7 documentation

# Översättning

## Översikt

För att göra ett Django-projekt översättningsbart måste du lägga till ett minimalt antal hooks i din Python-kod och mallar. Dessa hooks kallas översättningssträngar. De berättar för Django: ”Den här texten ska översättas till slutanvändarens språk, om en översättning för den här texten finns tillgänglig på det språket.” Det är ditt ansvar att markera översättningsbara strängar; systemet kan bara översätta strängar som det känner till.

Django tillhandahåller sedan verktyg för att extrahera översättningssträngarna till en message file. Denna fil är ett bekvämt sätt för översättare att tillhandahålla motsvarigheten till översättningssträngarna på målspråket. När översättarna har fyllt i meddelandefilen måste den kompileras. Denna process är beroende av GNU gettext-verktygsuppsättningen.

När detta är gjort tar Django hand om att översätta webbappar i farten på varje tillgängligt språk, enligt användarnas språkpreferenser.

Djangos internationaliserings-hooks är på som standard, och det betyder att det finns lite i18n-relaterad overhead på vissa ställen i ramverket. Om du inte använder internationalisering bör du ta två sekunder på dig att ställa in `USE_I18N = False` i din inställningsfil. Då kommer Django att göra vissa optimeringar så att internationaliseringsmaskineriet inte behöver laddas.

Observera

Se till att du har aktiverat översättning för ditt projekt (det snabbaste sättet är att kontrollera om `MIDDLEWARE` inkluderar `django.middleware.locale.LocaleMiddleware`). Om du inte har gjort det ännu, se hur-django-discovers-language-preference.

## Internationalisering: i Python-kod

### Standardöversättning

Ange en översättningssträng genom att använda funktionen `gettext()`. Det är konvention att importera detta som ett kortare alias, `_`, för att spara skrivning.

Observera

Pythons standardbiblioteksmodul `gettext` installerar `_()` i det globala namnrymden, som ett alias för `gettext()`. I Django har vi valt att inte följa denna praxis, av ett par skäl:

1. Ibland bör du använda `gettext_lazy()` som standardöversättningsmetod för en viss fil. Utan `_()` i det globala namnområdet måste utvecklaren tänka på vilken som är den mest lämpliga översättningsfunktionen.

2. Understreckstecknet (`_`) används för att representera ”det föregående resultatet” i Pythons interaktiva skal och doctest-tester. Att installera en global `_()`-funktion orsakar störningar. Explicit import av `gettext()` som `_()` undviker detta problem.

Vilka funktioner kan ha aliaset `_`?

På grund av hur `xgettext` (används av `makemessages`) fungerar, kan endast funktioner som tar ett enda strängargument importeras som `_`:

- `gettext()`

- `gettext_lazy()`

I det här exemplet markeras texten `"Välkommen till min webbplats."` som en översättningssträng:

    from django.http import HttpResponse
    from django.utils.translation import gettext as _

    def my_view(request):
        output = _("Welcome to my site.")
        return HttpResponse(output)

Du kan koda detta utan att använda aliaset. Detta exempel är identiskt med det föregående:

    from django.http import HttpResponse
    from django.utils.translation import gettext

    def my_view(request):
        output = gettext("Welcome to my site.")
        return HttpResponse(output)

Översättning fungerar på beräknade värden. Detta exempel är identiskt med de två föregående:

    def my_view(request):
        words = ["Welcome", "to", "my", "site."]
        output = _(" ".join(words))
        return HttpResponse(output)

Översättning fungerar på variabler. Återigen, här är ett identiskt exempel:

    def my_view(request):
        sentence = "Welcome to my site."
        output = _(sentence)
        return HttpResponse(output)

(Varningen med att använda variabler eller beräknade värden, som i de två föregående exemplen, är att Djangos verktyg för att upptäcka översättningssträngar, `django-admin makemessages`, inte kommer att kunna hitta dessa strängar. Mer om `makemessages` senare)

Strängarna som du skickar till `_()` eller `gettext()` kan innehålla platshållare som anges med Pythons standardiserade syntax för interpolering av namngivna strängar. Exempel:

    def my_view(request, m, d):
        output = _("Today is %(month)s %(day)s.") % {"month": m, "day": d}
        return HttpResponse(output)

Med den här tekniken kan språkspecifika översättningar ändra ordningen på platshållartexten. Till exempel kan en engelsk översättning vara ”Today is November 26.”, medan en spansk översättning kan vara ”Hoy es 26 de noviembre.” - med platshållarna för månad och dag ombytta.

Av denna anledning bör du använda namngiven stränginterpolering (t.ex. `%(day)s`) i stället för positionsinterpolering (t.ex. `%s` eller `%d`) när du har mer än en enda parameter. Om du använde positionell interpolering skulle översättningarna inte kunna ändra ordningen på platshållartexten.

Since string extraction is done by the `xgettext` command, only syntaxes supported by `gettext` are supported by Django. Python f-strings cannot be used directly with `gettext` functions because f-string expressions are evaluated before they reach `gettext`. This means `_(f"Welcome {name}")` will not work as expected, as the variable is substituted before translation occurs. Instead, use named-string interpolation:

    # Good
    _("Welcome %(name)s") % {"name": name}

    # Good
    _("Welcome {name}").format(name=name)

    # Bad
    _(f"Welcome {name}")  # f-string evaluated before translation.

JavaScript-mallsträngar kräver `gettext` 0.21+.

### Kommentarer för översättare

Om du vill ge översättarna tips om en översättningsbar sträng kan du lägga till en kommentar med nyckelordet `Translators` som prefix på raden före strängen, t.ex.:

    def my_view(request):
        # Translators: This message appears on the home page only
        output = gettext("Welcome to my site.")

Kommentaren kommer sedan att visas i den resulterande filen `.po` som är associerad med den översättningsbara konstruktionen som finns under den och bör också visas av de flesta översättningsverktyg.

Observera

Bara för fullständighetens skull är detta motsvarande fragment av den resulterande `.po`-filen:

    #. Translators: This message appears on the home page only
    # path/to/python/file.py:123
    msgid "Welcome to my site."
    msgstr ""

Detta fungerar även i mallar. Se Kommentarer för översättare i mallar för mer information.

### Markera strängar som no-op

Use the function `django.utils.translation.gettext_noop()` to mark a string as a translation string without translating it. The string is later translated from a variable.

Använd detta om du har konstanta strängar som bör lagras på källspråket eftersom de utbyts mellan system eller användare - t.ex. strängar i en databas - men som bör översättas vid sista möjliga tidpunkt, t.ex. när strängen presenteras för användaren.

### Pluralisering

Use the function `django.utils.translation.ngettext()` to specify pluralized messages.

`ngettext()` tar tre argument: översättningssträngen i singular, översättningssträngen i plural och antalet objekt.

Den här funktionen är användbar när du vill att din Django-applikation ska kunna lokaliseras till språk där antalet och komplexiteten i pluralformerna <https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ är större än de två former som används på engelska (”object” för singular och ”objects” för alla fall där ”count” skiljer sig från ett, oavsett dess värde)

Till exempel:

    from django.http import HttpResponse
    from django.utils.translation import ngettext

    def hello_world(request, count):
        page = ngettext(
            "there is %(count)d object",
            "there are %(count)d objects",
            count,
        ) % {
            "count": count,
        }
        return HttpResponse(page)

I det här exemplet skickas antalet objekt till översättningsspråken som variabeln ”count”.

Observera att pluralisering är komplicerat och fungerar olika på olika språk. Att jämföra `count` med 1 är inte alltid den korrekta regeln. Den här koden ser sofistikerad ut, men kommer att ge felaktiga resultat för vissa språk:

    from django.utils.translation import ngettext
    from myapp.models import Report

    count = Report.objects.count()
    if count == 1:
        name = Report._meta.verbose_name
    else:
        name = Report._meta.verbose_name_plural

    text = ngettext(
        "There is %(count)d %(name)s available.",
        "There are %(count)d %(name)s available.",
        count,
    ) % {"count": count, "name": name}

Försök inte att implementera din egen singular-eller-plural-logik; den kommer inte att vara korrekt. I ett fall som detta kan man tänka sig något i stil med följande:

    text = ngettext(
        "There is %(count)d %(name)s object available.",
        "There are %(count)d %(name)s objects available.",
        count,
    ) % {
        "count": count,
        "name": Report._meta.verbose_name,
    }

Observera

När du använder `ngettext()`, se till att du använder ett enda namn för varje extrapolerad variabel som ingår i den bokstavliga texten. I exemplen ovan, notera hur vi använde Python-variabeln `name` i båda översättningssträngarna. Detta exempel skulle, förutom att det är felaktigt på vissa språk enligt ovan, misslyckas:

    text = ngettext(
        "There is %(count)d %(name)s available.",
        "There are %(count)d %(plural_name)s available.",
        count,
    ) % {
        "count": Report.objects.count(),
        "name": Report._meta.verbose_name,
        "plural_name": Report._meta.verbose_name_plural,
    }

Du skulle få ett fel när du kör `django-admin compilemessages`:

    a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'

### Kontextuella markörer

Sometimes words have several meanings, such as `"May"` in English, which refers to a month name and to a verb. To enable translators to translate these words correctly in different contexts, you can use the `django.utils.translation.pgettext()` function, or the `django.utils.translation.npgettext()` function if the string needs pluralization. Both take a context string as the first variable.

I den resulterande `.po`-filen kommer strängen sedan att visas så ofta som det finns olika kontextuella markörer för samma sträng (kontexten visas på `msgctxt`-raden), vilket gör det möjligt för översättaren att ge en annan översättning för var och en av dem.

Till exempel:

    from django.utils.translation import pgettext

    month = pgettext("month name", "May")

eller:

    from django.db import models
    from django.utils.translation import pgettext_lazy

    class MyThing(models.Model):
        name = models.CharField(
            help_text=pgettext_lazy("help text for MyThing model", "This is the help text")
        )

kommer att visas i filen `.po` som:

    msgctxt "month name"
    msgid "May"
    msgstr ""

Kontextuella markörer stöds också av malltaggarna `translate` och `blocktranslate`.

### Lat översättning

Använd de lata versionerna av översättningsfunktioner i `django.utils.translation` (lätt igenkännliga genom suffixet `lazy` i deras namn) för att översätta strängar lata – när värdet nås snarare än när de anropas.

Dessa funktioner lagrar en latent referens till strängen - inte den faktiska översättningen. Själva översättningen görs när strängen används i en strängkontext, t.ex. i mallrendering.

Detta är viktigt när anrop till dessa funktioner finns i kodvägar som exekveras vid modulens laddningstid.

Detta är något som lätt kan hända när man definierar modeller, formulär och modellformulär, eftersom Django implementerar dessa så att deras fält faktiskt är attribut på klassnivå. Se därför till att använda lazy translations i följande fall:

#### Modellfält och relationer `verbose_name` och `help_text` alternativvärden

Om du t.ex. vill översätta hjälptexten för fältet name i följande modell gör du så här:

    from django.db import models
    from django.utils.translation import gettext_lazy as _

    class MyThing(models.Model):
        name = models.CharField(help_text=_("This is the help text"))

Du kan markera namn på `ForeignKey`, `ManyToManyField` eller `OneToOneField` relationer som översättningsbara genom att använda deras `verbose_name` alternativ:

    class MyThing(models.Model):
        kind = models.ForeignKey(
            ThingKind,
            on_delete=models.CASCADE,
            related_name="kinds",
            verbose_name=_("kind"),
        )

Precis som du skulle göra i `verbose_name` bör du ange en text med små bokstäver för verbose-namnet för relationen eftersom Django automatiskt kommer att skriva det med små bokstäver när det krävs.

#### Modell utförliga namn värden

Det rekommenderas att alltid tillhandahålla explicita `verbose_name` och `verbose_name_plural` alternativ snarare än att förlita sig på den engelska-centrerade och något naiva bestämningen av verbose-namn som Django utför genom att titta på modellens klassnamn:

    from django.db import models
    from django.utils.translation import gettext_lazy as _

    class MyThing(models.Model):
        name = models.CharField(_("name"), help_text=_("This is the help text"))

        class Meta:
            verbose_name = _("my thing")
            verbose_name_plural = _("my things")

#### Modellmetoder `description` argument till `@display` dekoratorn

För modellmetoder kan du tillhandahålla översättningar till Django och admin-webbplatsen med argumentet `description` till `display()` decorator:

    from django.contrib import admin
    from django.db import models
    from django.utils.translation import gettext_lazy as _

    class MyThing(models.Model):
        kind = models.ForeignKey(
            ThingKind,
            on_delete=models.CASCADE,
            related_name="kinds",
            verbose_name=_("kind"),
        )

        @admin.display(description=_("Is it a mouse?"))
        def is_mouse(self):
            return self.kind.type == MOUSE_TYPE

### Arbeta med objekt för latent översättning

Resultatet av ett `gettext_lazy()`-anrop kan användas där du skulle använda en sträng (ett `str`-objekt) i annan Django-kod, men det kanske inte fungerar med godtycklig Python-kod. Till exempel kommer följande inte att fungera eftersom biblioteket requests inte hanterar `gettext_lazy`-objekt:

    body = gettext_lazy("I \u2764 Django")  # (Unicode :heart:)
    requests.post("https://example.com/send", data={"body": body})

Du kan undvika sådana problem genom att kasta `gettext_lazy()`-objekt till textsträngar innan du skickar dem till icke-Django-kod:

    requests.post("https://example.com/send", data={"body": str(body)})

Om du inte gillar det långa namnet `gettext_lazy` kan du använda aliaset `_` (understreck), så här:

    from django.db import models
    from django.utils.translation import gettext_lazy as _

    class MyThing(models.Model):
        name = models.CharField(help_text=_("This is the help text"))

Att använda `gettext_lazy()` och `ngettext_lazy()` för att markera strängar i modeller och verktygsfunktioner är en vanlig operation. När du arbetar med dessa objekt på andra ställen i din kod bör du se till att du inte av misstag konverterar dem till strängar, eftersom de bör konverteras så sent som möjligt (så att rätt lokal används). Detta gör det nödvändigt att använda den hjälpfunktion som beskrivs härnäst.

#### Lata översättningar och plural

När du använder latent översättning för en pluralsträng (`n[p]gettext_lazy`) känner du i allmänhet inte till argumentet `number` vid tidpunkten för strängdefinitionen. Därför är du behörig att skicka ett nyckelnamn istället för ett heltal som argumentet `number`. Då kommer `number` att slås upp i ordlistan under den nyckeln vid stränginterpolering. Här är ett exempel:

    from django import forms
    from django.core.exceptions import ValidationError
    from django.utils.translation import ngettext_lazy

    class MyForm(forms.Form):
        error_message = ngettext_lazy(
            "You only provided %(num)d argument",
            "You only provided %(num)d arguments",
            "num",
        )

        def clean(self):
            # ...
            if error:
                raise ValidationError(self.error_message % {"num": number})

Om strängen innehåller exakt en icke namngiven platshållare kan du interpolerar direkt med argumentet `number`:

    class MyForm(forms.Form):
        error_message = ngettext_lazy(
            "You provided %d argument",
            "You provided %d arguments",
        )

        def clean(self):
            # ...
            if error:
                raise ValidationError(self.error_message % number)

#### Formatering av strängar: `format_lazy()`

Python’s `str.format()` method will not work when either the `format_string` or any of the arguments to `str.format()` contains lazy translation objects. Instead, you can use `django.utils.text.format_lazy()`, which creates a lazy object that runs the `str.format()` method only when the result is included in a string. For example:

    from django.utils.text import format_lazy
    from django.utils.translation import gettext_lazy

    ...
    name = gettext_lazy("John Lennon")
    instrument = gettext_lazy("guitar")
    result = format_lazy("{name}: {instrument}", name=name, instrument=instrument)

I det här fallet kommer de lata översättningarna i `result` endast att konverteras till strängar när `result` själv används i en sträng (vanligtvis vid mallens renderingstid).

#### Andra användningar av lazy i försenade översättningar

För alla andra fall där du vill fördröja översättningen, men måste skicka den översättningsbara strängen som argument till en annan funktion, kan du själv packa in den här funktionen i ett lazy call. Till exempel:

    from django.utils.functional import lazy
    from django.utils.translation import gettext_lazy as _

    def to_lower(string):
        return string.lower()

    to_lower_lazy = lazy(to_lower, str)

Och sedan senare:

    lazy_string = to_lower_lazy(_("My STRING!"))

### Lokaliserade namn på språk

get_language_info(lang_code)

Funktionen `get_language_info()` ger detaljerad information om språk:

    >>> from django.utils.translation import activate, get_language_info
    >>> activate("fr")
    >>> li = get_language_info("de")
    >>> print(li["name"], li["name_local"], li["name_translated"], li["bidi"])
    German Deutsch Allemand False

The `name`, `name_local`, and `name_translated` attributes of the dictionary contain the name of the language in English, in the language itself, and in your current active language respectively. The `bidi` attribute is True only for bi-directional languages.

Källan till språkinformationen är modulen `django.conf.locale`. Liknande tillgång till denna information är tillgänglig för mallkod. Se nedan.

## Internationalisering: i mallkod

Översättningar i Django templates använder två malltaggar och en något annorlunda syntax än i Python-kod. För att ge din mall tillgång till dessa taggar, lägg `{% load i18n %}` längst upp i din mall. Som med alla malltaggar måste denna tagg laddas i alla mallar som använder översättningar, även de mallar som bygger på andra mallar som redan har laddat `i18n`-taggen.

Varning

Översatta strängar kommer inte att escapas när de återges i en mall. Detta gör att du kan inkludera HTML i översättningar, t.ex. för att betona, men potentiellt farliga tecken (t.ex. `"`) kommer också att återges oförändrade.

### `translate` mall tagg

Malltaggen `{% translate %}` översätter antingen en konstant sträng (omgiven av enkla eller dubbla citattecken) eller variabelt innehåll:

    <title>{% translate "This is the title." %}</title>
    <title>{% translate myvar %}</title>

Om alternativet `noop` finns kvar sker fortfarande variabeluppslagning, men översättningen hoppas över. Detta är användbart när man ”stubbar ut” innehåll som kommer att behöva översättas i framtiden:

    <title>{% translate "myvar" noop %}</title>

Internt använder inline-översättningar ett `gettext()`-anrop.

Om en mallvariabel (`myvar` ovan) skickas till taggen kommer taggen först att omvandla variabeln till en sträng under körningen och sedan leta upp strängen i meddelandekatalogen.

Det är inte möjligt att blanda en mallvariabel i en sträng inom `{% translate %}`. Om dina översättningar kräver strängar med variabler (platshållare), använd `{% blocktranslate %}` istället.

Om du vill hämta en översatt sträng utan att visa den kan du använda följande syntax:

    {% translate "This is the title" as the_title %}

    <title>{{ the_title }}</title>
    <meta name="description" content="{{ the_title }}">

I praktiken använder du detta för att få en sträng som du kan använda på flera ställen i en mall eller så att du kan använda utdata som ett argument för andra malltaggar eller filter:

    {% translate "starting point" as start %}
    {% translate "end point" as end %}
    {% translate "La Grande Boucle" as race %}

    <h1>
      <a href="/" title="{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}">{{ race }}</a>
    </h1>
    <p>
    {% for stage in tour_stages %}
        {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br>{% else %}, {% endif %}
    {% endfor %}
    </p>

`{% translate %}` stöder även kontextuella markörer med hjälp av nyckelordet `context`:

    {% translate "May" context "month name" %}

### `blocktranslate` mall tagg

I motsats till taggen `translate` kan du med taggen `blocktranslate` markera komplexa meningar som består av bokstavstecken och variabelt innehåll för översättning genom att använda platshållare:

    {% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}

För att översätta ett malluttryck - t.ex. åtkomst till objektattribut eller användning av mallfilter - måste du binda uttrycket till en lokal variabel som kan användas i översättningsblocket. Exempel på detta:

    {% blocktranslate with amount=article.price %}
    That will cost $ {{ amount }}.
    {% endblocktranslate %}

    {% blocktranslate with myvar=value|filter %}
    This will have {{ myvar }} inside.
    {% endblocktranslate %}

Du kan använda flera uttryck i en enda `blocktranslate`-tagg:

    {% blocktranslate with book_t=book|title author_t=author|title %}
    This is {{ book_t }} by {{ author_t }}
    {% endblocktranslate %}

Observera

Det tidigare mer utförliga formatet stöds fortfarande: `{% blocktranslate med book|title som book_t och author|title som author_t %}`

Andra blocktaggar (till exempel `{% for %}` eller `{% if %}`) är inte tillåtna inuti en `blocktranslate`-tagg.

Om lösningen av ett av blockargumenten misslyckas kommer `blocktranslate` att falla tillbaka till standardspråket genom att avaktivera det aktuella aktiva språket tillfälligt med funktionen `deactivate_all()`.

Den här taggen möjliggör även pluralisering. För att använda den:

- Utse och bind ett räknevärde med namnet `count`. Detta värde kommer att vara det som används för att välja rätt pluralform.

- Ange både singular- och pluralformerna och separera dem med taggen `{% plural %}` i taggarna `{% blocktranslate %}` och `{% endblocktranslate %}`.

Ett exempel:

    {% blocktranslate count counter=list|length %}
    There is {{ counter }} {{ name }} object.
    {% plural %}
    There are {{ counter }} {{ name }} objects.
    {% endblocktranslate %}

Ett mer komplext exempel:

    {% blocktranslate with amount=article.price count years=i.length %}
    That will cost $ {{ amount }} per year.
    {% plural %}
    That will cost $ {{ amount }} per {{ years }} years.
    {% endblocktranslate %}

När du använder både pluraliseringsfunktionen och binder värden till lokala variabler utöver räknevärdet, kom ihåg att `blocktranslate`-konstruktionen internt konverteras till ett `ngettext`-anrop. Detta innebär att samma noteringar om ngettext-variabler gäller.

Omvända URL-uppslagningar kan inte utföras inom `blocktranslate` och bör hämtas (och lagras) i förväg:

    {% url 'path.to.view' arg arg2 as the_url %}
    {% blocktranslate %}
    This is a URL: {{ the_url }}
    {% endblocktranslate %}

Om du vill hämta en översatt sträng utan att visa den kan du använda följande syntax:

    {% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
    <title>{{ the_title }}</title>
    <meta name="description" content="{{ the_title }}">

I praktiken använder du detta för att få en sträng som du kan använda på flera ställen i en mall eller så att du kan använda utdata som ett argument för andra malltaggar eller filter.

`{% blocktranslate %}` stöder även kontextuella markörer med hjälp av nyckelordet `context`:

    {% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}

En annan funktion som stöds av `{% blocktranslate %}` är alternativet `trimmed`. Detta alternativ tar bort ny rad-tecken från början och slutet av innehållet i taggen `{% blocktranslate %}`, ersätter alla blanksteg i början och slutet av en rad och sammanfogar alla rader till en med ett mellanslagstecken för att separera dem. Detta är mycket användbart för att indentera innehållet i en `{% blocktranslate %}`-tagg utan att indentationstecknen hamnar i motsvarande post i filen `.po`, vilket gör översättningsprocessen enklare.

Till exempel följande tagg `{% blocktranslate %}`:

    {% blocktranslate trimmed %}
      First sentence.
      Second paragraph.
    {% endblocktranslate %}

kommer att resultera i posten `"Första meningen. Second paragraph."` i filen `.po`, jämfört med `"\n First sentence.\n Second paragraph.\n"`, om alternativet `trimmed` inte hade angetts.

### Stränglitteraler som skickas till taggar och filter

Du kan översätta stränglitteraler som skickas som argument till taggar och filter genom att använda den välbekanta syntaxen `_()`:

    {% some_tag _("Page not found") value|yesno:_("yes,no") %}

I det här fallet kommer både taggen och filtret att se den översatta strängen, så de behöver inte vara medvetna om översättningar.

Observera

I det här exemplet kommer översättningsinfrastrukturen att få strängen ”yes,no”, inte de enskilda strängarna ”yes” och ”no”. Den översatta strängen måste innehålla ett kommatecken så att filterparsningskoden vet hur argumenten ska delas upp. En tysk översättare kan till exempel översätta strängen `"yes,no"` till `"ja,nein"` (med kommatecknet intakt).

### Kommentarer för översättare i mallar

Precis som med Python-kod kan dessa anteckningar för översättare anges med hjälp av kommentarer, antingen med taggen `comment`:

    {% comment %}Translators: View verb{% endcomment %}
    {% translate "View" %}

    {% comment %}Translators: Short intro blurb{% endcomment %}
    <p>{% blocktranslate %}A multiline translatable
    literal.{% endblocktranslate %}</p>

eller med `{#` … `#}` enradskommentarer konstrueras:

    {# Translators: Label of a button that triggers search #}
    <button type="submit">{% translate "Go" %}</button>

    {# Translators: This is a text of the base template #}
    {% blocktranslate %}Ambiguous translatable block of text{% endblocktranslate %}

Observera

Bara för fullständighetens skull är detta motsvarande fragment av den resulterande `.po`-filen:

    #. Translators: View verb
    # path/to/template/file.html:10
    msgid "View"
    msgstr ""

    #. Translators: Short intro blurb
    # path/to/template/file.html:13
    msgid ""
    "A multiline translatable"
    "literal."
    msgstr ""

    # ...

    #. Translators: Label of a button that triggers search
    # path/to/template/file.html:100
    msgid "Go"
    msgstr ""

    #. Translators: This is a text of the base template
    # path/to/template/file.html:103
    msgid "Ambiguous translatable block of text"
    msgstr ""

### Byte av språk i mallar

Om du vill välja ett språk i en mall kan du använda malltaggen `language`:

    {% load i18n %}

    {% get_current_language as LANGUAGE_CODE %}
    <!-- Current language: {{ LANGUAGE_CODE }} -->
    <p>{% translate "Welcome to our page" %}</p>

    {% language 'en' %}
        {% get_current_language as LANGUAGE_CODE %}
        <!-- Current language: {{ LANGUAGE_CODE }} -->
        <p>{% translate "Welcome to our page" %}</p>
    {% endlanguage %}

Medan den första förekomsten av ”Välkommen till vår sida” använder det aktuella språket, kommer den andra alltid att vara på engelska.

### Andra taggar

Dessa taggar kräver också en `{% load i18n %}`.

#### `hämta_tillgängliga_språk`

`{% get_available_languages as LANGUAGES %}` returnerar en lista med tupler där det första elementet är språkkoden och det andra är språknamnet (översatt till den aktuella lokala språkdräkten).

#### `hämta aktuellt språk`

`{% get_current_language as LANGUAGE_CODE %}` returnerar den aktuella användarens föredragna språk som en sträng. Exempel: `en-us`. Se Hur Django upptäcker språkpreferenser.

#### `get_current_language_bidi`

`{% get_current_language_bidi as LANGUAGE_BIDI %}` returnerar den aktuella lokalens riktning. Om `True`, är det ett höger-till-vänster-språk, t.ex. hebreiska, arabiska. Om `False` är det ett vänster-till-höger-språk, t.ex. engelska, franska, tyska etc.

#### `i18n` kontextprocessor

Om du aktiverar kontextprocessorn `django.template.context_processors.i18n`, kommer varje `RequestContext` att ha tillgång till `LANGUAGES`, `LANGUAGE_CODE` och `LANGUAGE_BIDI` enligt definitionen ovan.

#### hämta språkinformation

Du kan också hämta information om vilket som helst av de tillgängliga språken med hjälp av malltaggar och filter. För att få information om ett enda språk använder du taggen `{% get_language_info %}`:

    {% get_language_info for LANGUAGE_CODE as lang %}
    {% get_language_info for "pl" as lang %}

Du kan sedan komma åt informationen:

    Language code: {{ lang.code }}<br>
    Name of language: {{ lang.name_local }}<br>
    Name in English: {{ lang.name }}<br>
    Bi-directional: {{ lang.bidi }}
    Name in the active language: {{ lang.name_translated }}

#### hämta språkinfo-lista

Du kan också använda malltaggen `{% get_language_info_list %}` för att hämta information för en lista med språk (t.ex. aktiva språk som anges i `LANGUAGES`). Se avsnittet om set_language redirect view för ett exempel på hur man visar en språkväljare med hjälp av `{% get_language_info_list %}`.

Förutom `LANGUAGES` stil lista av tuples, `{% get_language_info_list %}` stöder listor av språkkoder. Om du gör detta i din vy:

    context = {"available_languages": ["en", "es", "fr"]}
    return render(request, "mytemplate.html", context)

kan du iterera över dessa språk i mallen:

    {% get_language_info_list for available_languages as langs %}
    {% for lang in langs %} ... {% endfor %}

#### Mallfilter

Det finns också några filter tillgängliga för bekvämlighetens skull:

- `{{ LANGUAGE_CODE|language_name }}` (”tyska”)

- `{{ LANGUAGE_CODE|språknamn_lokal }}` (”Deutsch”)

- `{{ LANGUAGE_CODE|language_bidi }}` (Falsk)

- `{{ LANGUAGE_CODE|language_name_translated }}` (”německy”, när det aktiva språket är tjeckiska)

## Internationalisering: i JavaScript-kod

Att lägga till översättningar i JavaScript innebär vissa problem:

- JavaScript-kod har inte tillgång till en `gettext`-implementering.

- JavaScript-kod har inte tillgång till filerna `.po` eller `.mo`, utan de måste levereras av servern.

- Översättningskatalogerna för JavaScript bör hållas så små som möjligt.

Django erbjuder en integrerad lösning för dessa problem: Översättningarna skickas till JavaScript, så att du kan anropa `gettext` etc. från JavaScript.

Den huvudsakliga lösningen på dessa problem är följande vy `JavaScriptCatalog`, som genererar ett JavaScript-kodbibliotek med funktioner som efterliknar gränssnittet `gettext`, plus en matris med översättningssträngar.

### Vyn `JavaScriptCatalog` (JavaScript-katalog)

class JavaScriptCatalog

  En vy som producerar ett JavaScript-kodbibliotek med funktioner som efterliknar gränssnittet `gettext`, plus en matris med översättningssträngar.

  Attribut

  domain

    Översättningsdomän som innehåller strängar som ska läggas till i vyns utdata. Standardvärdet är `'djangojs`.

  packages

    A list of application names (`AppConfig.name`) among the installed applications. Those apps should contain a `locale` directory. All those catalogs plus all catalogs found in `LOCALE_PATHS` (which are always included) are merged into one catalog. Defaults to `None`, which means that all available translations from all `INSTALLED_APPS` are provided in the JavaScript output.

  Exempel med standardvärden:

      from django.views.i18n import JavaScriptCatalog

      urlpatterns = [
          path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"),
      ]

  Exempel med anpassade paket:

      urlpatterns = [
          path(
              "jsi18n/myapp/",
              JavaScriptCatalog.as_view(packages=["your.app.label"]),
              name="javascript-catalog",
          ),
      ]

  Om din root URLconf använder `i18n_patterns()`, måste `JavaScriptCatalog` också omslutas av `i18n_patterns()` för att katalogen ska genereras korrekt.

  Exempel med `i18n_patterns()`:

      from django.conf.urls.i18n import i18n_patterns

      urlpatterns = i18n_patterns(
          path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"),
      )

Översättningarnas prioritet är sådan att de paket som förekommer senare i argumentet `packages` har högre prioritet än de som förekommer i början. Detta är viktigt när det gäller krockande översättningar för samma bokstav.

Om du använder mer än en `JavaScriptCatalog`-vy på en webbplats och några av dem definierar samma strängar, har strängarna i den katalog som laddades senast företräde.

### Använda JavaScript-översättningskatalogen

För att använda katalogen drar du in det dynamiskt genererade skriptet så här:

    <script src="{% url 'javascript-catalog' %}"></script>

Detta använder omvänd URL-uppslagning för att hitta URL:en för JavaScript-katalogvyn. När katalogen är laddad kan din JavaScript-kod använda följande metoder:

- `gettext`

- `ngettext`

- `interpolera`

- `get_format`

- `gettext_noop`

- `pgettext`

- `npgettext`

- `pluralidx`

#### `gettext`

Funktionen `gettext` beter sig på samma sätt som standardgränssnittet `gettext` i din Python-kod:

    document.write(gettext("this is to be translated"))

#### `ngettext`

Funktionen `ngettext` tillhandahåller ett gränssnitt för att pluralisera ord och fraser:

    const objectCount = 1 // or 0, or 2, or 3, ...
    const string = ngettext(
        'literal for the singular case',
        'literal for the plural case',
        objectCount
    );

#### `interpolera`

Funktionen `interpolate` har stöd för att dynamiskt fylla i en formatsträng. Interpolationssyntaxen är lånad från Python, så funktionen `interpolate` stöder både positions- och namninterpolation:

- Positionell interpolering: `obj` innehåller ett JavaScript Array-objekt vars elementvärden sedan interpoleras sekventiellt i motsvarande `fmt`-platshållare i samma ordning som de visas. Till exempel:

      const formats = ngettext(
        'There is %s object. Remaining: %s',
        'There are %s objects. Remaining: %s',
        11
      );
      const string = interpolate(formats, [11, 20]);
      // string is 'There are 11 objects. Remaining: 20'

- Namngiven interpolation: Detta läge väljs genom att skicka den valfria booleska parametern `named` som `true`. `obj` innehåller ett JavaScript-objekt eller en associativ matris. Exempelvis:

      const data = {
        count: 10,
        total: 50
      };

      const formats = ngettext(
          'Total: %(total)s, there is %(count)s object',
          'there are %(count)s of a total of %(total)s objects',
          data.count
      );
      const string = interpolate(formats, data, true);

Du bör dock inte överdriva med stränginterpolering: det här är fortfarande JavaScript, så koden måste göra upprepade substitutioner med reguljära uttryck. Detta är inte lika snabbt som stränginterpolering i Python, så håll det till de fall där du verkligen behöver det (till exempel i samband med `ngettext` för att producera korrekta pluraliseringar).

#### `get_format`

Funktionen `get_format` har tillgång till de konfigurerade i18n-formateringsinställningarna och kan hämta formatsträngen för ett givet inställningsnamn:

    document.write(get_format('DATE_FORMAT'));
    // 'N j, Y'

Den har tillgång till följande inställningar:

- `DATE_FORMAT`

- `DATE_INPUT_FORMATS`

- `DATETIME_FORMAT`

- `DATETIME_INPUT_FORMATS`

- `DECIMAL_SEPARATOR`

- `FÖRSTA_DAGEN_I_VECKAN`

- `MONTH_DAY_FORMAT`

- `NUMBER_GROUPING`

- `SHORT_DATE_FORMAT`

- `SHORT_DATETIME_FORMAT`

- `THOUSAND_SEPARATOR`

- `TIME_FORMAT`

- `TIME_INPUT_FORMATS`

- `YEAR_MONTH_FORMAT`

Detta är användbart för att upprätthålla formateringskonsistens med de Python-renderade värdena.

#### `gettext_noop`

Detta efterliknar funktionen `gettext` men gör ingenting, utan returnerar det som skickas till den:

    document.write(gettext_noop("this will not be translated"))

Det här är användbart för att stubba ut delar av koden som kommer att behöva översättas i framtiden.

#### `pgettext`

The `pgettext` function behaves like the Python variant (`pgettext()`), providing a contextually translated word:

    document.write(pgettext("month name", "May"))

#### `npgettext`

The `npgettext` function also behaves like the Python variant (`npgettext()`), providing a pluralized contextually translated word:

    document.write(npgettext('group', 'party', 1));
    // party
    document.write(npgettext('group', 'party', 2));
    // parties

#### `pluralidx`

Funktionen `pluralidx` fungerar på samma sätt som mallfiltret `pluralize` och avgör om ett givet `count` ska använda pluralformen av ett ord eller inte:

    document.write(pluralidx(0));
    // true
    document.write(pluralidx(1));
    // false
    document.write(pluralidx(2));
    // true

I det enklaste fallet, om ingen anpassad pluralisering behövs, returnerar detta `false` för heltalet `1` och `true` för alla andra tal.

Pluralisering är dock inte lika enkelt på alla språk. Om språket inte stöder pluralisering anges ett tomt värde.

Om det dessutom finns komplexa regler kring pluralisering, kommer katalogvyn att återge ett villkorligt uttryck. Detta utvärderas till antingen ett `true` (bör pluraliseras) eller `false` (bör inte pluraliseras) värde.

### Vyn ”JSONCatalog

class JSONCatalog

  För att använda ett annat bibliotek på klientsidan för att hantera översättningar kanske du vill dra nytta av vyn `JSONCatalog`. Den liknar `JavaScriptCatalog` men returnerar ett JSON-svar.

  Se dokumentationen för `JavaScriptCatalog` för att lära dig mer om möjliga värden och användning av attributen `domain` och `packages`.

  Svarsformatet är som följer:

      {
          "catalog": {
              # Translations catalog
          },
          "formats": {
              # Language formats for date, time, etc.
          },
          "plural": "..."  # Expression for plural forms, or null.
      }

### Not om prestanda

De olika JavaScript/JSON i18n-vyerna genererar katalogen från `.mo`-filer vid varje förfrågan. Eftersom dess utdata är konstant, åtminstone för en viss version av en webbplats, är det en bra kandidat för cachelagring.

Cachelagring på serversidan minskar CPU-belastningen. Det är enkelt att implementera med `cache_page()` decorator. För att utlösa cache-invalidering när dina översättningar ändras, ange ett versionsberoende nyckelprefix, som visas i exemplet nedan, eller mappa vyn på en versionsberoende URL:

    from django.views.decorators.cache import cache_page
    from django.views.i18n import JavaScriptCatalog

    # The value returned by get_version() must change when translations change.
    urlpatterns = [
        path(
            "jsi18n/",
            cache_page(86400, key_prefix="jsi18n-%s" % get_version())(
                JavaScriptCatalog.as_view()
            ),
            name="javascript-catalog",
        ),
    ]

Cachelagring på klientsidan sparar bandbredd och gör att din webbplats laddas snabbare. Om du använder ETags (`ConditionalGetMiddleware`) är du redan täckt. Annars kan du tillämpa villkorliga dekoratorer. I följande exempel ogiltigförklaras cachen när du startar om din applikationsserver:

    from django.utils import timezone
    from django.views.decorators.http import last_modified
    from django.views.i18n import JavaScriptCatalog

    last_modified_date = timezone.now()

    urlpatterns = [
        path(
            "jsi18n/",
            last_modified(lambda req, **kw: last_modified_date)(
                JavaScriptCatalog.as_view()
            ),
            name="javascript-catalog",
        ),
    ]

Du kan till och med förgenerera JavaScript-katalogen som en del av din distributionsprocedur och servera den som en statisk fil. Denna radikala teknik implementeras i django-statici18n.

## Internationalisering: i URL-mönster

Django tillhandahåller två mekanismer för att internationalisera URL-mönster:

- Lägger till språkprefixet i roten av URL-mönstren för att göra det möjligt för `LocaleMiddleware` att upptäcka vilket språk som ska aktiveras från den begärda URL:en.

- Making URL patterns themselves translatable via the `django.utils.translation.gettext_lazy()` function.

Varning

För att använda någon av dessa funktioner krävs att ett aktivt språk ställs in för varje begäran; med andra ord måste du ha `django.middleware.locale.LocaleMiddleware` i din `MIDDLEWARE`-inställning.

### Språkprefix i URL-mönster

i18n_patterns(*urls, prefix_default_language=True)

Denna funktion kan användas i en rot-URLconf och Django kommer automatiskt att preppa den aktuella aktiva språkkoden till alla URL-mönster som definieras inom `i18n_patterns()`.

Om du anger `prefix_default_language` till `False` tas prefixet bort från standardspråket (`LANGUAGE_CODE`). Detta kan vara användbart när du lägger till översättningar på en befintlig webbplats så att de aktuella webbadresserna inte ändras.

Exempel på URL-mönster:

    from django.conf.urls.i18n import i18n_patterns
    from django.urls import include, path

    from about import views as about_views
    from news import views as news_views
    from sitemap.views import sitemap

    urlpatterns = [
        path("sitemap.xml", sitemap, name="sitemap-xml"),
    ]

    news_patterns = (
        [
            path("", news_views.index, name="index"),
            path("category/<slug:slug>/", news_views.category, name="category"),
            path("<slug:slug>/", news_views.details, name="detail"),
        ],
        "news",
    )

    urlpatterns += i18n_patterns(
        path("about/", about_views.main, name="about"),
        path("news/", include(news_patterns, namespace="news")),
    )

Efter att ha definierat dessa URL-mönster kommer Django automatiskt att lägga till språkprefixet till de URL-mönster som lades till av funktionen `i18n_patterns`. Exempel på detta:

    >>> from django.urls import reverse
    >>> from django.utils.translation import activate

    >>> activate("en")
    >>> reverse("sitemap-xml")
    '/sitemap.xml'
    >>> reverse("news:index")
    '/en/news/'

    >>> activate("nl")
    >>> reverse("news:detail", kwargs={"slug": "news-slug"})
    '/nl/news/news-slug/'

Med `prefix_default_language=False` och `LANGUAGE_CODE='en'` blir webbadresserna följande:

    >>> activate("en")
    >>> reverse("news:index")
    '/news/'

    >>> activate("nl")
    >>> reverse("news:index")
    '/nl/news/'

Varning

`i18n_patterns()` är endast tillåtet i en root URLconf. Om du använder den i en inkluderad URLconf kommer du att få ett `ImproperlyConfigured` undantag.

Varning

Se till att du inte har icke-prefixerade URL-mönster som kan kollidera med ett automatiskt tillagt språkprefix.

### Översättning av URL-mönster

URL-mönster kan också markeras som översättningsbara med hjälp av funktionen `gettext_lazy()`. Exempel:

    from django.conf.urls.i18n import i18n_patterns
    from django.urls import include, path
    from django.utils.translation import gettext_lazy as _

    from about import views as about_views
    from news import views as news_views
    from sitemaps.views import sitemap

    urlpatterns = [
        path("sitemap.xml", sitemap, name="sitemap-xml"),
    ]

    news_patterns = (
        [
            path("", news_views.index, name="index"),
            path(_("category/<slug:slug>/"), news_views.category, name="category"),
            path("<slug:slug>/", news_views.details, name="detail"),
        ],
        "news",
    )

    urlpatterns += i18n_patterns(
        path(_("about/"), about_views.main, name="about"),
        path(_("news/"), include(news_patterns, namespace="news")),
    )

När du har skapat översättningarna kommer funktionen `reverse()` att returnera webbadressen på det aktiva språket. Exempel på detta:

    >>> from django.urls import reverse
    >>> from django.utils.translation import activate

    >>> activate("en")
    >>> reverse("news:category", kwargs={"slug": "recent"})
    '/en/news/category/recent/'

    >>> activate("nl")
    >>> reverse("news:category", kwargs={"slug": "recent"})
    '/nl/nieuws/categorie/recent/'

Varning

I de flesta fall är det bäst att använda översatta webbadresser endast inom ett språkkodsprefixerat block av mönster (med `i18n_patterns()`), för att undvika risken att en slarvigt översatt webbadress orsakar en kollision med ett icke-översatt webbadressmönster.

### Omvändning i mallar

Om lokaliserade webbadresser blir omvända i mallar använder de alltid det aktuella språket. Om du vill länka till en URL på ett annat språk använder du malltaggen `language`. Den aktiverar det angivna språket i det bifogade mallavsnittet:

    {% load i18n %}

    {% get_available_languages as languages %}

    {% translate "View this category in:" %}
    {% for lang_code, lang_name in languages %}
        {% language lang_code %}
        <a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
        {% endlanguage %}
    {% endfor %}

Taggen `language` förväntar sig språkkoden som det enda argumentet.

## Lokalisering: hur man skapar språkfiler

När stränglitteralerna i en applikation har taggats för senare översättning, måste själva översättningen skrivas (eller erhållas). Så här fungerar det.

### Meddelandefiler

Det första steget är att skapa en message file för ett nytt språk. En meddelandefil är en fil i klartext som representerar ett enda språk och som innehåller alla tillgängliga översättningssträngar och hur de ska representeras på det aktuella språket. Meddelandefiler har filändelsen `.po`.

Django levereras med ett verktyg, `django-admin makemessages`, som automatiserar skapandet och underhållet av dessa filer.

Gettext-verktyg

Kommandot `makemessages` (och `compilemessages` som diskuteras senare) använder kommandon från GNU gettext toolset: `xgettext`, `msgfmt`, `msgmerge` och `msguniq`.

Den minsta versionen av `gettext`-verktygen som stöds är 0.19.

Kör det här kommandot för att skapa eller uppdatera en meddelandefil:

    django-admin makemessages -l de

…där `de` är lokalnamn för den meddelandefil du vill skapa. Till exempel `pt_BR` för brasiliansk portugisiska, `de_AT` för österrikisk tyska eller `id` för indonesiska.

Skriptet bör köras från en av två platser:

- Rotkatalogen för ditt Django-projekt (den som innehåller `manage.py`).

- Rotkatalogen för en av dina Django-appar.

Skriptet körs över projektets källträd eller applikationens källträd och drar ut alla strängar som är markerade för översättning (se Hur Django upptäcker översättningar och se till att `LOCALE_PATHS` är korrekt konfigurerad). Det skapar (eller uppdaterar) en meddelandefil i katalogen `locale/LANG/LC_MESSAGES`. I exemplet `de` kommer filen att vara `locale/de/LC_MESSAGES/django.po`.

När du kör `makemessages` från rotkatalogen i ditt projekt, kommer de extraherade strängarna automatiskt att distribueras till rätt meddelandefiler. Det vill säga, en sträng som extraheras från en fil i en app som innehåller en `locale`-katalog kommer att hamna i en meddelandefil under den katalogen. En sträng som extraheras från en fil i en app utan någon `locale`-katalog kommer antingen att läggas i en meddelandefil under den katalog som listas först i `LOCALE_PATHS` eller generera ett fel om `LOCALE_PATHS` är tom.

Som standard undersöker `django-admin makemessages` alla filer som har filtillägget `.html`, `.txt` eller `.py`. Om du vill åsidosätta denna standard använder du alternativet `--extension` eller `-e` för att ange vilka filtillägg som ska undersökas:

    django-admin makemessages -l de -e txt

Separera flera tillägg med kommatecken och/eller använd `-e` eller `--extension` flera gånger:

    django-admin makemessages -l de -e html,txt -e xml

Varning

När du skapar meddelandefiler från JavaScript-källkod måste du använda den speciella domänen `djangojs`, inte `-e js`.

Använda Jinja2-mallar?

`makemessages` förstår inte syntaxen i Jinja2-mallar. För att extrahera strängar från ett projekt som innehåller Jinja2-mallar, använd Message Extracting från Babel istället.

Här är ett exempel på konfigurationsfilen `babel.cfg`:

    # Extraction from Python source files
    [python: **.py]

    # Extraction from Jinja2 templates
    [jinja2: **.jinja]
    extensions = jinja2.ext.with_

Se till att du listar alla tillägg du använder! Annars kommer Babel inte att känna igen de taggar som definieras av dessa tillägg och kommer att ignorera Jinja2-mallar som innehåller dem helt och hållet.

Babel tillhandahåller liknande funktioner som `makemessages`, kan ersätta det i allmänhet och är inte beroende av `gettext`. För mer information, läs dess dokumentation om att arbeta med meddelandekataloger.

Ingen gettext?

Om du inte har verktygen `gettext` installerade kommer `makemessages` att skapa tomma filer. Om så är fallet, installera antingen `gettext`-verktygen eller kopiera den engelska meddelandefilen (`locale/en/LC_MESSAGES/django.po`) om den finns tillgänglig och använd den som utgångspunkt, vilket är en tom översättningsfil.

Arbetar du på Windows?

Om du använder Windows och behöver installera GNU:s gettext-verktyg för att `makemessages` ska fungera, se gettext på Windows för mer information.

Varje `.po`-fil innehåller en liten del metadata, till exempel kontaktuppgifter till den som ansvarar för översättningen, men huvuddelen av filen är en lista med messages - mappningar mellan översättningssträngar och den faktiska översatta texten för det aktuella språket.

Till exempel, om din Django-app innehåller en översättningssträng för texten `"Välkommen till min webbplats."`, så här:

    _("Welcome to my site.")

…då kommer `django-admin makemessages` att ha skapat en `.po`-fil som innehåller följande utdrag – ett meddelande:

    #: path/to/python/module.py:23
    msgid "Welcome to my site."
    msgstr ""

En snabb förklaring:

- `msgid` är översättningssträngen, som visas i källan. Ändra inte den.

- `msgstr` är där du lägger in den språkspecifika översättningen. Den är tom från början, så det är ditt ansvar att ändra den. Se till att du behåller citattecknen runt din översättning.

- För enkelhetens skull innehåller varje meddelande, i form av en kommentarrad med `#` som prefix och ovanför `msgid`-raden, filnamnet och radnumret från vilket översättningssträngen hämtades.

Långa meddelanden är ett specialfall. Där är den första strängen direkt efter `msgstr` (eller `msgid`) en tom sträng. Sedan skrivs själva innehållet över de närmaste raderna som en sträng per rad. Dessa strängar konkateneras direkt. Glöm inte efterföljande mellanslag i strängarna; annars kommer de att häftas ihop utan blanksteg!

Tänk på din charset

Due to the way the `gettext` tools work internally and because we want to allow non-ASCII source strings in Django’s core and your applications, you must use UTF-8 as the encoding for your `.po` files (the default when `.po` files are created). This means that everybody will be using the same encoding, which is important when Django processes the `.po` files.

Flummiga poster

`makemessages` genererar ibland översättningsposter som är markerade som luddiga, t.ex. när översättningar härleds från tidigare översatta strängar. Som standard bearbetas inte fuzzy-poster av `compilemessages`.

Om du vill granska all källkod och alla mallar för nya översättningssträngar och uppdatera alla meddelandefiler för alla språk kör du detta:

    django-admin makemessages -a

### Sammanställning av meddelandefiler

När du har skapat din meddelandefil - och varje gång du gör ändringar i den - måste du sammanställa den till en mer effektiv form som kan användas av `gettext`. Detta gör du med `django-admin compilemessages`.

Detta verktyg går igenom alla tillgängliga `.po`-filer och skapar `.mo`-filer, som är binära filer optimerade för att användas av `gettext`. I samma katalog som du körde `django-admin makemessages`, kör `django-admin compilemessages` så här:

    django-admin compilemessages

Nu är det klart. Dina översättningar är klara att användas.

Arbetar du på Windows?

Om du använder Windows och behöver installera GNU:s gettext-verktyg för att `django-admin compilemessages` ska fungera, se gettext på Windows för mer information.

`.po`-filer: Kodning och BOM-användning.

Django stöder endast `.po`-filer kodade i UTF-8 och utan någon BOM (Byte Order Mark) så om din textredigerare lägger till sådana märken i början av filer som standard måste du konfigurera om den.

### Felsökning: `gettext()` upptäcker felaktigt `python-format` i strängar med procenttecken

I vissa fall, till exempel strängar med ett procenttecken följt av ett mellanslag och en strängkonverteringstyp (t.ex. `_("10% interest")`), `gettext()` flaggar felaktigt strängar med `python-format`.

Om du försöker kompilera meddelandefiler med felaktigt markerade strängar får du ett felmeddelande som `antalet formatspecifikationer i 'msgid' och 'msgstr' matchar inte` eller `'msgstr' är inte en giltig Python-formatsträng, till skillnad från 'msgid'`.

För att kringgå detta kan du undkomma procenttecken genom att lägga till ett andra procenttecken:

    from django.utils.translation import gettext as _

    output = _("10%% interest")

Eller så kan du använda `no-python-format` så att alla procenttecken behandlas som bokstavstecken:

    # xgettext:no-python-format
    output = _("10% interest")

### Skapa meddelandefiler från JavaScript-källkod

Du skapar och uppdaterar meddelandefilerna på samma sätt som de andra Django-meddelandefilerna - med verktyget `django-admin makemessages`. Den enda skillnaden är att du uttryckligen måste ange vad som på gettextspråk kallas en domän, i det här fallet `djangojs`-domänen, genom att tillhandahålla en `-d djangojs`-parameter, så här:

    django-admin makemessages -d djangojs -l de

Detta skulle skapa eller uppdatera meddelandefilen för JavaScript för tyska. Efter uppdatering av meddelandefiler kör du `django-admin compilemessages` på samma sätt som du gör med vanliga Django-meddelandefiler.

### `gettext` på Windows

Detta behövs endast för personer som antingen vill extrahera meddelande-ID:n eller sammanställa meddelandefiler (`.po`). Själva översättningsarbetet innebär att redigera befintliga filer av den här typen, men om du vill skapa dina egna meddelandefiler, eller vill testa eller kompilera en ändrad meddelandefil, ladda ner en förkompilerad binär installerare.

Du kan också använda `gettext` binära filer som du har fått på annat håll, så länge kommandot `xgettext --version` fungerar korrekt. Försök inte att använda Djangos översättningsverktyg med ett `gettext`-paket om kommandot `xgettext --version` som anges i en Windows-kommandotolk orsakar ett popup-fönster som säger ”`xgettext.exe` har genererat fel och kommer att stängas av Windows”.

### Anpassa kommandot ”Makemessages

Om du vill skicka ytterligare parametrar till `xgettext` måste du skapa ett anpassat `makemessages`-kommando och åsidosätta dess `xgettext_options`-attribut:

    from django.core.management.commands import makemessages

    class Command(makemessages.Command):
        xgettext_options = makemessages.Command.xgettext_options + ["--keyword=mytrans"]

Om du behöver mer flexibilitet kan du också lägga till ett nytt argument till ditt anpassade `makemessages`-kommando:

    from django.core.management.commands import makemessages

    class Command(makemessages.Command):
        def add_arguments(self, parser):
            super().add_arguments(parser)
            parser.add_argument(
                "--extra-keyword",
                dest="xgettext_keywords",
                action="append",
            )

        def handle(self, *args, **options):
            xgettext_keywords = options.pop("xgettext_keywords")
            if xgettext_keywords:
                self.xgettext_options = makemessages.Command.xgettext_options[:] + [
                    "--keyword=%s" % kwd for kwd in xgettext_keywords
                ]
            super().handle(*args, **options)

## Diverse

### Omdirigeringsvyn ”set_language

set_language(request)

Som en bekvämlighet kommer Django med en vy, `django.views.i18n.set_language()`, som ställer in en användares språkpreferens och omdirigerar till en given URL eller, som standard, tillbaka till föregående sida.

Aktivera denna vy genom att lägga till följande rad i din URLconf:

    path("i18n/", include("django.conf.urls.i18n")),

(Observera att detta exempel gör vyn tillgänglig på `/i18n/setlang/`.)

Varning

Se till att du inte inkluderar ovanstående URL inom `i18n_patterns()` - den måste vara språkoberoende själv för att fungera korrekt.

Vyn förväntas anropas via metoden `POST`, med en parameter `language` inställd i begäran. Vyn sparar språkvalet i en cookie som standard heter `django_language`. (Namnet kan ändras genom inställningen `LANGUAGE_COOKIE_NAME`.)

Efter att ha ställt in språkvalet letar Django efter en `next` parameter i `POST` eller `GET` data. Om den hittas och Django anser att det är en säker URL (dvs. den pekar inte till en annan värd och använder ett säkert schema), kommer en omdirigering till den URL:en att utföras. Annars kan Django falla tillbaka till att omdirigera användaren till webbadressen från `Referer`-huvudet eller, om det inte är inställt, till `/`, beroende på typen av begäran:

- Om begäran accepterar HTML-innehåll (baserat på HTTP-rubriken `Accept`) utförs alltid fallbacken.

- Om begäran inte accepterar HTML, kommer fallbacken endast att utföras om parametern `next` har angetts. I annat fall returneras en statuskod 204 (Inget innehåll).

Här är ett exempel på HTML-mallkod:

    {% load i18n %}

    <form action="{% url 'set_language' %}" method="post">{% csrf_token %}
        <input name="next" type="hidden" value="{{ redirect_to }}">
        <select name="language">
            {% get_current_language as LANGUAGE_CODE %}
            {% get_available_languages as LANGUAGES %}
            {% get_language_info_list for LANGUAGES as languages %}
            {% for language in languages %}
                <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
                    {{ language.name_local }} ({{ language.code }})
                </option>
            {% endfor %}
        </select>
        <input type="submit" value="Go">
    </form>

I det här exemplet letar Django upp webbadressen till den sida som användaren kommer att omdirigeras till i kontextvariabeln `redirect_to`.

### Explicit inställning av det aktiva språket

You may want to set the active language for the current session explicitly. Perhaps a user’s language preference is retrieved from another system, for example. You’ve already been introduced to `django.utils.translation.activate()`. That applies to the current thread only. To persist the language for the entire session in a cookie, set the `LANGUAGE_COOKIE_NAME` cookie on the response:

    from django.conf import settings
    from django.http import HttpResponse
    from django.utils import translation

    user_language = "fr"
    translation.activate(user_language)
    response = HttpResponse(...)
    response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)

You would typically want to use both: `django.utils.translation.activate()` changes the language for this thread, and setting the cookie makes this preference persist in future requests.

### Använda översättningar utanför vyer och mallar

Även om Django tillhandahåller en rik uppsättning i18n-verktyg för användning i vyer och mallar, begränsar det inte användningen till Django-specifik kod. Djangos översättningsmekanismer kan användas för att översätta godtyckliga texter till alla språk som stöds av Django (så länge som en lämplig översättningskatalog finns, naturligtvis). Du kan ladda en översättningskatalog, aktivera den och översätta text till valfritt språk, men kom ihåg att växla tillbaka till originalspråket, eftersom aktivering av en översättningskatalog görs per tråd och en sådan ändring kommer att påverka kod som körs i samma tråd.

Till exempel:

    from django.utils import translation

    def welcome_translated(language):
        cur_language = translation.get_language()
        try:
            translation.activate(language)
            text = translation.gettext("welcome")
        finally:
            translation.activate(cur_language)
        return text

Anrop av denna funktion med värdet `'de'` ger dig `"Willkommen"`, oavsett `LANGUAGE_CODE` och språk som anges av mellanprogramvaran.

Functions of particular interest are `django.utils.translation.get_language()` which returns the language used in the current thread, `django.utils.translation.activate()` which activates a translation catalog for the current thread, and `django.utils.translation.check_for_language()` which checks if the given language is supported by Django.

To help write more concise code, there is also a context manager `django.utils.translation.override()` that stores the current language on enter and restores it on exit. With it, the above example becomes:

    from django.utils import translation

    def welcome_translated(language):
        with translation.override(language):
            return translation.gettext("welcome")

### Cookie för språk

Ett antal inställningar kan användas för att justera alternativen för språkcookies:

- `LANGUAGE_COOKIE_NAME`

- `LANGUAGE_COOKIE_AGE`

- `LANGUAGE_COOKIE_DOMAIN`

- `LANGUAGE_COOKIE_HTTPONLY`

- `LANGUAGE_COOKIE_PATH`

- `LANGUAGE_COOKIE_SAMESITE`

- `LANGUAGE_COOKIE_SECURE`

## Anteckningar om implementering

### Specialiteter inom Django-översättning

Djangos översättningsmaskineri använder standardmodulen `gettext` som medföljer Python. Om du känner till `gettext` kanske du noterar dessa specialiteter i hur Django gör översättning:

- Strängdomänen är `django` eller `djangojs`. Denna strängdomän används för att skilja mellan olika program som lagrar sina data i ett gemensamt meddelandefilsbibliotek (vanligtvis `/usr/share/locale/`). Domänen `django` används för översättningssträngar för Python och mallar och laddas in i de globala översättningskatalogerna. Domänen `djangojs` används endast för JavaScript-översättningskataloger för att se till att de är så små som möjligt.

- Django använder inte enbart `xgettext`. Det använder Pythonomslag runt `xgettext` och `msgfmt`. Detta är mest för bekvämlighetens skull.

### Hur Django upptäcker språkpreferenser

När du har förberett dina översättningar - eller om du vill använda de översättningar som följer med Django - måste du aktivera översättning för din app.

Bakom kulisserna har Django en mycket flexibel modell för att bestämma vilket språk som ska användas - installationsövergripande, för en viss användare eller båda.

För att ställa in en installationsomfattande språkpreferens, ställ in `LANGUAGE_CODE`. Django använder detta språk som standardöversättning - det sista försöket om ingen bättre matchande översättning hittas genom någon av de metoder som används av locale middleware (se nedan).

Om allt du vill är att köra Django med ditt modersmål behöver du bara ställa in `LANGUAGE_CODE` och se till att motsvarande message files och deras kompilerade versioner (`.mo`) finns.

Om du vill låta varje enskild användare ange vilket språk de föredrar måste du också använda `LocaleMiddleware`. `LocaleMiddleware` möjliggör språkval baserat på data från begäran. Det anpassar innehållet för varje användare.

För att använda `LocaleMiddleware`, lägg till `'django.middleware.locale.LocaleMiddleware'` till din `MIDDLEWARE` inställning. Eftersom ordningen på middleware spelar roll, följ dessa riktlinjer:

- Se till att det är en av de första middleware som installeras.

- Det bör komma efter `SessionMiddleware`, eftersom `LocaleMiddleware` använder sessionsdata. Och det bör komma före `CommonMiddleware` eftersom `CommonMiddleware` behöver ett aktiverat språk för att kunna lösa den begärda URL:en.

- Om du använder `CacheMiddleware`, lägg till `LocaleMiddleware` efter det.

Till exempel kan din `MIDDLEWARE` se ut så här:

    MIDDLEWARE = [
        "django.contrib.sessions.middleware.SessionMiddleware",
        "django.middleware.locale.LocaleMiddleware",
        "django.middleware.common.CommonMiddleware",
    ]

(Mer information om middleware finns i middleware documentation.)

`LocaleMiddleware` försöker bestämma användarens språkpreferens genom att följa denna algoritm:

- First, it looks for the language prefix in the requested URL. This is only performed when you are using the `i18n_patterns` function in your root URLconf. See Internationalisering: i URL-mönster for more information about the language prefix and how to internationalize URL patterns.

- Om det inte lyckas letar den efter en kaka.

  Namnet på den cookie som används bestäms av inställningen `LANGUAGE_COOKIE_NAME`. (Standardnamnet är `django_language`.)

- Om så inte är fallet tittar den på HTTP-huvudet ”Accept-Language”. Denna header skickas av din webbläsare och talar om för servern vilket eller vilka språk du föredrar, i prioritetsordning. Django provar varje språk i rubriken tills den hittar ett med tillgängliga översättningar.

- Om så inte är fallet används den globala inställningen `LANGUAGE_CODE`.

Anteckningar:

- På var och en av dessa platser förväntas språkpreferensen vara i standard language format, som en sträng. Till exempel är brasiliansk portugisiska `pt-br`.

- Om ett basspråk är tillgängligt men det angivna underspråket inte är det, använder Django basspråket. Till exempel, om en användare anger `de-at` (österrikisk tyska) men Django bara har `de` tillgängligt, använder Django `de`.

- Endast de språk som anges i inställningen `LANGUAGES` kan väljas. Om du vill begränsa språkvalet till en delmängd av de språk som tillhandahålls (eftersom ditt program inte tillhandahåller alla dessa språk) anger du `LANGUAGES` till en lista med språk. Till exempel:

      LANGUAGES = [
          ("de", _("German")),
          ("en", _("English")),
      ]

  I det här exemplet begränsas de språk som är tillgängliga för automatiskt val till tyska och engelska (och alla underspråk, som `de-ch` eller `en-us`).

- Om du definierar en anpassad `LANGUAGES`-inställning, som förklaras i föregående punkt, kan du markera språknamnen som översättningssträngar - men använd `gettext_lazy()` istället för `gettext()` för att undvika en cirkulär import.

  Här är ett exempel på en inställningsfil:

      from django.utils.translation import gettext_lazy as _

      LANGUAGES = [
          ("de", _("German")),
          ("en", _("English")),
      ]

När `LocaleMiddleware` har bestämt användarens preferens gör den denna preferens tillgänglig som `request.LANGUAGE_CODE` för varje `HttpRequest`. Läs gärna detta värde i din view-kod. Här är ett exempel:

    from django.http import HttpResponse

    def hello_world(request, count):
        if request.LANGUAGE_CODE == "de-at":
            return HttpResponse("You prefer to read Austrian German.")
        else:
            return HttpResponse("You prefer to read another language.")

Observera att med statisk översättning (utan middleware) finns språket i `settings.LANGUAGE_CODE`, medan det med dynamisk översättning (middleware) finns i `request.LANGUAGE_CODE`.

### Hur Django upptäcker översättningar

Vid körning bygger Django en enhetlig katalog av bokstavs-översättningar i minnet. För att uppnå detta letar den efter översättningar genom att följa denna algoritm angående ordningen i vilken den undersöker de olika filsökvägarna för att ladda de kompilerade meddelandefilerna (`.mo`) och företräde för flera översättningar för samma bokstav:

1. De kataloger som anges i `LOCALE_PATHS` har högst prioritet, där de som visas först har högre prioritet än de som visas senare.

2. Then, it looks for and uses if it exists a `locale` directory in each of the installed apps listed in `INSTALLED_APPS`. The ones appearing first have higher precedence than the ones appearing later.

3. Slutligen används den Django-tillhandahållna basöversättningen i django/conf/locale som en fallback.

Se även

Översättningarna för literaler som ingår i JavaScript-tillgångar söks upp enligt en liknande men inte identisk algoritm. Se `JavaScriptCatalog` för mer information.

Du kan också placera custom format files i `LOCALE_PATHS`-katalogerna om du också anger `FORMAT_MODULE_PATH`.

I samtliga fall förväntas namnet på den katalog som innehåller översättningen vara namngivet med locale name-notation. T.ex. `de`, `pt_BR`, `es_AR`, etc. Oöversatta strängar för territoriella språkvarianter använder översättningarna av det generiska språket. Till exempel, oöversatta `pt_BR` strängar använder `pt` översättningar.

På så sätt kan du skriva program som innehåller sina egna översättningar och du kan åsidosätta basöversättningar i ditt projekt. Eller så kan du bygga ett stort projekt av flera appar och lägga alla översättningar i en stor gemensam meddelandefil som är specifik för det projekt du skapar. Valet är ditt.

Alla arkiv för meddelandefiler är uppbyggda på samma sätt. De är följande:

- Alla sökvägar som anges i `LOCALE_PATHS` i din inställningsfil söks efter `<language>/LC_MESSAGES/django.(po|mo)`

- `$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`

- `$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)`

För att skapa meddelandefiler använder du verktyget `django-admin makemessages`. Och du använder `django-admin compilemessages` för att producera de binära `.mo`-filerna som används av `gettext`.

Du kan också köra `django-admin compilemessages --settings=path.to.settings` för att få kompilatorn att bearbeta alla kataloger i din `LOCALE_PATHS`-inställning.

### Användning av ett icke-engelskt basspråk

Django gör det allmänna antagandet att originalsträngarna i ett översättningsbart projekt är skrivna på engelska. Du kan välja ett annat språk, men du måste vara medveten om vissa begränsningar:

- `gettext` ger bara två pluralformer för de ursprungliga meddelandena, så du måste också tillhandahålla en översättning för basspråket för att inkludera alla pluralformer om pluralreglerna för basspråket skiljer sig från engelska.

- När en engelsk variant är aktiverad och engelska strängar saknas, kommer reservspråket inte att vara projektets `LANGUAGE_CODE`, utan originalsträngarna. Till exempel kommer en engelsk användare som besöker en webbplats med `LANGUAGE_CODE` inställt på spanska och originalsträngar skrivna på ryska att se rysk text i stället för spansk.