masonite icon indicating copy to clipboard operation
masonite copied to clipboard

RFC: add translations handling

Open resmo opened this issue 3 years ago • 0 comments

I like to implement a translation handling using gettext, here is what I did:

given a template with translations e.g. in welcome.html

{{ _("Translation") }} 

create locales path

mkdir -p locales/de/LC_MESSAGES/

create a po file base.po in that locales path

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-08-22 08:36+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

msgid "Translation"
msgstr "Übersetzung"

generate a mo file from po file (gnu gettext)

cd locales/de/LC_MESSAGES/
msgfmt base.po

final tree

|-- locales
|   `-- de
|       `-- LC_MESSAGES
|           |-- base.mo
|           `-- base.po

created a config/locale.py with available translations:

LANGUAGES = ["en", "de"]
DEFAULT_LANUGAGE = "en"

created a language middleware to parse the browser header of accepted languages and compare with available translations list from a created config locale.py

import os

from masonite.facades import Config
from masonite.middleware import Middleware


def parseAcceptLanguage(acceptLanguage):
    languages = acceptLanguage.split(",")
    locale_q_pairs = []

    for language in languages:
        if language.split(";")[0] == language:
            # no q => q = 1
            locale_q_pairs.append((language.strip(), "1"))
        else:
            locale = language.split(";")[0].strip()
            q = language.split(";")[1].split("=")[1]
            locale_q_pairs.append((locale, q))

    return locale_q_pairs


class LanguageMiddleware(Middleware):
    def before(self, request, response):
        languages = Config.get("locale.languages")
        accpeted_languages = parseAcceptLanguage(request.header("Accept-Language"))
        for accpeted_language in accpeted_languages:
            al, q = accpeted_language
            if al in languages:
                language = al
                break
        else:
            language = Config.get("locale.default_language")

        os.environ["LANGUAGE"] = language
        return request

    def after(self, request, response):
        return request

Things missing:

  • ~change language based on header accept language?~
  • test for the path locale/ is probably not ideal, enable/disable using conf?

resmo avatar Sep 18 '22 10:09 resmo