Skip to main content

Exposing Translations to JavaScript

To expose server-side internationalization strings to your client-side JavaScript, use the JavaScriptCatalog view. This view generates a JavaScript library that provides functions like gettext and ngettext populated with your project's translations.

Setting up the Translation Catalog

To make the catalog available, add the JavaScriptCatalog view to your URL configuration.

# urls.py
from django.urls import path
from django.views.i18n import JavaScriptCatalog

urlpatterns = [
# Expose translations for all installed apps
path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

By default, JavaScriptCatalog looks for translations in the djangojs domain. When creating your message files, you must specify this domain:

python manage.py makemessages -d djangojs -l de

Restricting Translations to Specific Packages

If you only want to expose translations from specific applications (e.g., to reduce the size of the generated JavaScript file), provide a packages list to the as_view() method. This is how the Django admin limits its catalog:

# Example from django/contrib/admin/sites.py
from django.views.i18n import JavaScriptCatalog

# In your urls.py
path('admin/jsi18n/', JavaScriptCatalog.as_view(packages=['django.contrib.admin']), name='admin-jsi18n'),

Using Translations in JavaScript

Once the URL is configured, include the generated script in your HTML template. You can then use the standard translation functions in your JavaScript code.

<!-- In your template -->
<script src="{% url 'javascript-catalog' %}"></script>
<script>
// Basic translation
const welcome = gettext("Welcome to my site.");

// Pluralization
// ngettext(singular, plural, count)
const count = 5;
const message = ngettext("%s item", "%s items", count);

// String interpolation
const formatted = interpolate(message, [count]);

console.log(formatted); // "5 items" (if translated)
</script>

The catalog also exposes locale-specific formatting via get_format():

const dateFormat = get_format('DATE_FORMAT');

Exposing Translations as JSON

If you are building a single-page application (SPA) or prefer to handle translation logic yourself, use JSONCatalog. It returns the same data structure as a JSON object instead of a JavaScript library.

# urls.py
from django.views.i18n import JSONCatalog

urlpatterns = [
path('jsi18n/json/', JSONCatalog.as_view(), name='json-catalog'),
]

The response from JSONCatalog follows this structure:

{
"catalog": {
"Welcome to my site.": "Willkommen auf meiner Seite.",
"%s item": ["%s Element", "%s Elemente"]
},
"formats": {
"DATE_FORMAT": "N j, Y",
"NUMBER_GROUPING": 3
},
"plural": "n != 1"
}

Troubleshooting

Missing Packages

If you specify a package in the packages argument that is not found in INSTALLED_APPS, JavaScriptCatalog will raise a ValueError.

# django/views/i18n.py
def get_paths(self, packages):
# ...
if len(app_configs) < len(packages):
excluded = [p for p in packages if p not in allowable_packages]
raise ValueError(
"Invalid package(s) provided to JavaScriptCatalog: %s"
% ",".join(excluded)
)

Translations Not Appearing

Ensure your strings are marked for translation in the djangojs domain. Strings in the default django domain (from .po files generated without -d djangojs) are not included in the JavaScriptCatalog by default. You can override this by setting the domain attribute in your URL configuration:

path('jsi18n/', JavaScriptCatalog.as_view(domain='django'), name='javascript-catalog'),