Switch language in jinja template

I have this code snippet to switch between languages in jinja2.

def change_lang(request, lang=None, *args, **kwargs):
Get active page's url by a specified language, it activates 
Usage: {{ change_lang(request, 'en') }}

path = request.path
url_parts = resolve(path)

url = path
cur_language = get_language()
    url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)

return "%s" % url

in settings.py

    "BACKEND": "django_jinja.backend.Jinja2",
    'DIRS': [
        os.path.join(BASE_DIR, 'templates/jinja'),
    "OPTIONS": {
        # Match the template names ending in .html but not the ones in the admin folder.
        "match_extension": ".html",
        "match_regex": r"^(?!admin/).*",
        "newstyle_gettext": True,
        "extensions": [
        'globals': {
            'change_lang': 'drug.utils.change_lang'
        "bytecode_cache": {
            "name": "default",
            "backend": "django_jinja.cache.BytecodeCache",
            "enabled": False,
        "autoescape": True,
        "auto_reload": DEBUG,
        "translation_engine": "django.utils.translation",
        "context_processors": [
            # "django.template.context_processors.debug",
            # "django.template.context_processors.media",
            # "django.template.context_processors.static",
            # "django.template.context_processors.tz",
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [
        os.path.join(BASE_DIR, 'templates'),
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [

and then you can use this in anywhere in your templates {{ _('Hello World') }}

It turns out it's fairly simple to do this by writing a custom jinja2 extension (I've based this on the example in the jinja2 docs):

from django.utils import translation
from jinja2.ext import Extension, nodes

class LanguageExtension(Extension):
    tags = {'language'}

    def parse(self, parser):
        lineno = next(parser.stream).lineno
        # Parse the language code argument
        args = [parser.parse_expression()]
        # Parse everything between the start and end tag:
        body = parser.parse_statements(['name:endlanguage'], drop_needle=True)
        # Call the _switch_language method with the given language code and body
        return nodes.CallBlock(self.call_method('_switch_language', args), [], [], body).set_lineno(lineno)

    def _switch_language(self, language_code, caller):
        with translation.override(language_code):
            # Temporarily override the active language and render the body
            output = caller()
        return output

# Add jinja2's i18n extension
# Install Django's translation module as the gettext provider
env.install_gettext_translations(translation, newstyle=True)
# Add the language extension to the jinja2 environment

With this extension in place switching the active translation language is pretty much exactly like how you'd do it in Django:

{% language 'en' %}{{ _('Hello World'){% endlanguage %}

The only caveat is that when using Django as a gettext provider and Babel as a message extractor it's important to tell Babel to set the message domain to django when running init/update/compile_catalog.