Open StikyFingaz opened 4 months ago
Hello I think you have missed adding the babel to the Fastapi middleware. please have a look at the examples.
from fastapi_babel import Babel, BabelConfigs, BabelMiddleware
from fastapi_babel.core import _
app = FastAPI()
babel_configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)
app.add_middleware(
BabelMiddleware, babel_configs=babel_configs
)
@app.get("/")
async def index():
return {"text": _("Hello World")}
also, you can use the depends
from fastapi_babel import Babel, BabelConfigs, BabelMiddleware
from fastapi_babel.core import make_gettext
app = FastAPI()
babel_configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)
app.add_middleware(
BabelMiddleware, babel_configs=babel_configs
)
@app.get("/")
async def index(_: Annotated[Callable[[str], str], Depends(make_gettext)]):
return {"text": _("Hello World")}
It seems that a minimal app works as expected as shown in your examples. However, in order to get strings from my API router, I had to use both gettext
and make_gettext
:
from typing import Annotated, Callable
from fastapi import APIRouter, Depends
from fastapi_babel.core import gettext as _
from fastapi_babel.core import make_gettext
router = APIRouter(
prefix='/translations',
tags=['translations'],
dependencies=[],
responses={}
)
@router.get('/')
async def fetch_common_strings(_: Annotated[Callable[[str], str], Depends(make_gettext)]):
translated_strings = {k: _(v) for k, v in common_strings.items()}
return translated_strings
common_strings = {
'title': _('My Page Title'),
}
This was not the case in v0.0.8. Is this a reasonable approach?
If you want to use _('WORD')
outside of the request context (API scope)
you have to use the lazy_gettext.
The best solution is:
create the file messages.py
and write the code below.
...
from fastapi_babel.core import lazy_gettext as _
common_strings = {
'title': _('My Page Title'),
}
and use the from fastapi_babel import _
in other files.
Why you should use the lazygettext instead of simple `` outside of the request context?
because _
depends on the request object and the income header to change the babel.locale
. when you use that outside of the specific scope you must get the Context error.
so the ideal solution is to use the lazy_gettext instead of that.
Note You cannot import the lazy_gettext side by side of the simple gettext. I'd like to refer you to the Django documentation about this topic to get my statements. also, lazygettext never translates any text so we use it only for extracting messages to use throughout the files and APIs using real gettext `()`.
In this example, I've demonstrated the usage of the lazy_gettext for translating wtform input labels. https://github.com/Anbarryprojects/fastapi-babel/blob/main/examples/wtforms/forms.py
Thank you for your help.
Hi!
First of all, thank you for this amazing library! I'd like to reopen this issue because I have a similar problem and I wasn't able to solve it. I'm using Version: 0.0.9.
In my application I use the _()
inside a worker function using ThreadPoolExecutor. The error I'm receiving is the same as @StikyFingaz 's:
\fastapi_babel\core.py", line 123, in _
gettext = _context_var.get()
LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30>
Here's a simplified version of my issue, which still illustrates the problem
from fastapi_babel import Babel, BabelConfigs, BabelMiddleware
from fastapi_babel.core import _
from fastapi import FastAPI, Header
from typing_extensions import Annotated
from typing import Union, Callable
from concurrent.futures import ThreadPoolExecutor, as_completed
app = FastAPI()
babel_configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)
app.add_middleware(
BabelMiddleware, babel_configs=babel_configs
)
# Passes, no problemo
@app.get("/test0")
async def func_0(accept_language: Annotated[Union[str, None], Header()] = None):
return {"text": _("Hello, World!")}
def getHW():
return _("Hello, World!")
# Still passes, no problemo
@app.get("/test1")
async def func_1(accept_language: Annotated[Union[str, None], Header()] = None):
return {"text": getHW()}
# LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30> :(
@app.get("/test2")
async def func_2(accept_language: Annotated[Union[str, None], Header()] = None
):
future_to_index = {}
index_to_result = {}
with ThreadPoolExecutor() as executor:
future_to_index = {executor.submit(getHW): i for i in range(10)}
for future in as_completed(future_to_index):
index = future_to_index[future]
res = future.result()
index_to_result[index] = res
return {"text": index_to_result}
Do you have any suggestions on how to resolve this issue @Legopapurida ? I read your comment mentioning lazy_gettext, but I was not able to apply it to my case...
Updating to 0.0.9 breaks my app. This happened again with 0.0.8. I think @Legopapurida might be going in circles on this one. I don't have the time to try to find a workaround so I downgraded to 0.0.8. If you don't have problems with that version you might stick with it for now. It works perfectly fine for me.
Hi!
First of all, thank you for this amazing library! I'd like to reopen this issue because I have a similar problem and I wasn't able to solve it. I'm using Version: 0.0.9.
In my application I use the
_()
inside a worker function using ThreadPoolExecutor. The error I'm receiving is the same as @StikyFingaz 's:\fastapi_babel\core.py", line 123, in _ gettext = _context_var.get() LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30>
Here's a simplified version of my issue, which still illustrates the problem
from fastapi_babel import Babel, BabelConfigs, BabelMiddleware from fastapi_babel.core import _ from fastapi import FastAPI, Header from typing_extensions import Annotated from typing import Union, Callable from concurrent.futures import ThreadPoolExecutor, as_completed app = FastAPI() babel_configs = BabelConfigs( ROOT_DIR=__file__, BABEL_DEFAULT_LOCALE="en", BABEL_TRANSLATION_DIRECTORY="lang", ) app.add_middleware( BabelMiddleware, babel_configs=babel_configs ) # Passes, no problemo @app.get("/test0") async def func_0(accept_language: Annotated[Union[str, None], Header()] = None): return {"text": _("Hello, World!")} def getHW(): return _("Hello, World!") # Still passes, no problemo @app.get("/test1") async def func_1(accept_language: Annotated[Union[str, None], Header()] = None): return {"text": getHW()} # LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30> :( @app.get("/test2") async def func_2(accept_language: Annotated[Union[str, None], Header()] = None ): future_to_index = {} index_to_result = {} with ThreadPoolExecutor() as executor: future_to_index = {executor.submit(getHW): i for i in range(10)} for future in as_completed(future_to_index): index = future_to_index[future] res = future.result() index_to_result[index] = res return {"text": index_to_result}
Do you have any suggestions on how to resolve this issue @Legopapurida ? I read your comment mentioning lazy_gettext, but I was not able to apply it to my case...
Hello dear friend I've figured out your problem domain.
I should create a context invoker for resolving this problem.
You must use the FastAPI background task and make_gettext as dependency injection. you need to merge these two approaches to achieve the best result.
If you want to handle this issue without my idea, you may need to use the queue and thread shared memory concept.
please try those solutions, If you can't get good output please let me know to find a better way to handle this issue. Otherwise, I have to write a PushContext API to resolve the problem.
Hi,
I just want to say thank you for your work. I use fastapi-babel and it has been working fine so far.
After the latest update I get this:
Here is my config file:
Please note that I made a dependency to set the locale globally because using fastapi-babel as middleware was breaking my app in other ways.