Anbarryprojects / fastapi-babel

FastAPI babel support pybable tools like translation of text, formatting of dates, times and numbers, and time zones.
MIT License
46 stars 14 forks source link

Allow to use a cookie to select the locale #38

Open Garito opened 2 months ago

Garito commented 2 months ago

Hi Seems weird to me that these code doesn't allow to use this way to select the locale giving the fact that it is a very popular way

Even will be good if other methods were allowed

Any change to allow, at least, cookies?

Thanks

Legopapurida commented 2 weeks ago

Hello @Garito I will create a way to handle this issue

Legopapurida commented 2 weeks ago

@Garito I have added locale selector to control the locale param from request controller into middleware

Garito commented 1 week ago

Thanks @Legopapurida If this was a santa letter I will ask for a way to use cookies or header at the same time to allow using it as and API and as a normal app

Legopapurida commented 1 week ago

You can pass your locale selector from outside of the app context. Because we have to do rights as a book in Internationalization and locale selectors between all the frameworks such as Django, Flask, FastAPI, ... Well-known frameworks have inspired us.

look at the example from the Django application:


import webapp2
from webapp2_extras import i18n

AVAILABLE_LOCALES = ['en_GB', 'es_ES']

class BaseHandler(webapp2.RequestHandler):
    def __init__(self, request, response):
        """ Override the initialiser in order to set the language.
        """
        self.initialize(request, response)

        # first, try and set locale from cookie
        locale = request.cookies.get('locale')
        if locale in AVAILABLE_LOCALES:
            i18n.get_i18n().set_locale(locale)
        else:
            # if that failed, try and set locale from accept language header
            header = request.headers.get('Accept-Language', '')  # e.g. en-gb,en;q=0.8,es-es;q=0.5,eu;q=0.3
            locales = [locale.split(';')[0] for locale in header.split(',')]
            for locale in locales:
                if locale in AVAILABLE_LOCALES:
                    i18n.get_i18n().set_locale(locale)
                    break
            else:
                # if still no locale set, use the first available one
                i18n.get_i18n().set_locale(AVAILABLE_LOCALES[0])

import base

class Index(base.BaseHandler):
    """ Set the language cookie (if locale is valid), then redirect back to referrer
    """
    def get(self, locale):
        if locale in self.available_locales:
            self.response.set_cookie('locale', locale, max_age = 15724800)  # 26 weeks' worth of seconds

        # redirect to referrer or root
        url = self.request.headers.get('Referer', '/')
        self.redirect(url)

so you can pass your locale selector such as the above example which enables you to use Accept-Language from cookie or header even query param.

Garito commented 1 week ago

I'm already doing this:

lang_code: str | None = request.cookies.get('locale', None) or request.headers.get("Accept-Language", None)