Skip to content

Commit

Permalink
Merge pull request #32 from Anbarryprojects:v1
Browse files Browse the repository at this point in the history
[REF] Refactored examples by new changes.
  • Loading branch information
Legopapurida authored Feb 25, 2024
2 parents 588eb1e + bf36f70 commit f5badb8
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 68 deletions.
Binary file removed examples/test1/__pycache__/main.cpython-39.pyc
Binary file not shown.
32 changes: 15 additions & 17 deletions examples/test1/babel.py → examples/test1/i18n.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
from fastapi import FastAPI, Request

from fastapi_babel import Babel
from fastapi_babel import BabelConfigs
from fastapi_babel import _


configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)

babel: Babel = Babel(configs=configs)

if __name__ == "__main__":
babel.run_cli()
from fastapi_babel import Babel
from fastapi_babel import BabelConfigs
from fastapi_babel import _


configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)

babel: Babel = Babel(configs=configs)

if __name__ == "__main__":
babel.run_cli()
8 changes: 4 additions & 4 deletions examples/test1/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from _babel import _
from _babel import babel
from i18n import _
from i18n import babel

if __name__ == "__main__":
babel.locale = "en"
en_text = _("File not found. There is nothing here")
Expand All @@ -13,4 +13,4 @@
print(fr_text)
babel.locale = "es"
es_text = _("File not found. There is nothing here")
print(es_text)
print(es_text)
12 changes: 7 additions & 5 deletions examples/with_jinja/full.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
from fastapi.templating import Jinja2Templates

from fastapi_babel import _ # noqa
from fastapi_babel import Babel, BabelConfigs
from fastapi_babel import Babel, BabelConfigs, BabelMiddleware


app = FastAPI()
babel_configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)
templates = Jinja2Templates(directory="templates")
app.add_middleware(BabelMiddleware, babel_configs=babel_configs, jinja2_templates=templates)
app.add_middleware(
BabelMiddleware, babel_configs=babel_configs, jinja2_templates=templates
)
app.mount("/static", StaticFiles(directory="static"), name="static")


Expand Down
7 changes: 5 additions & 2 deletions examples/wtforms/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from i18n import babel
from fastapi_babel.middleware import BabelMiddleware


class Application:
Expand All @@ -13,8 +14,10 @@ def create_app() -> FastAPI:
root: Type[Application] = Application
root.app = FastAPI()
root.templates = Jinja2Templates(directory="templates")
babel.init_app(app=root.app)
babel.install_jinja(root.templates)
templates = Jinja2Templates(directory="templates")
root.app.add_middleware(
BabelMiddleware, babel_configs=babel.config, jinja2_templates=templates
)
from routes import router

root.app.include_router(router=router)
Expand Down
10 changes: 8 additions & 2 deletions fastapi_babel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
from .middleware import BabelMiddleware
from .properties import RootConfigs as BabelConfigs

__version__ = "0.0.8"
__version__ = "0.0.9"
__author__ = "[email protected]"
__all__ = ["Babel", "BabelCli", "BabelConfigs", "_"]
__all__ = [
"Babel",
"BabelCli",
"BabelConfigs",
"_",
"BabelMiddleware",
]
26 changes: 14 additions & 12 deletions fastapi_babel/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,23 +105,25 @@ def make_gettext(request: Request = Depends()) -> Callable[[str], str]:

def translate(message: str) -> str:
# Get Babel instance from request or fallback to the CLI instance (when defined)
babel = getattr(request.state, 'babel', Babel.instance)
babel = getattr(request.state, "babel", Babel.instance)
if babel is None:
raise BabelProxyError("Babel instance is not available in the current request context.")
raise BabelProxyError(
"Babel instance is not available in the current request context."
)

return babel.gettext(message)

return translate



_context_var: ContextVar[Callable[[str], str]] = ContextVar("gettext")


def _(message: str) -> str:
gettext = _context_var.get()
return gettext(message)


lazy_gettext = __LazyText


Expand All @@ -135,7 +137,7 @@ def __init__(self, babel: Babel) -> None:
Args:
babel (Babel): `Babel` instance
"""
Babel.instance: Babel = babel
self.babel = babel

def extract(self, watch_dir: str) -> None:
"""extract all messages that annotated using gettext/_
Expand All @@ -152,9 +154,9 @@ def extract(self, watch_dir: str) -> None:
BabelCli.__module_name__,
"extract",
"-F",
Babel.instance.config.BABEL_CONFIG_FILE,
self.babel.config.BABEL_CONFIG_FILE,
"-o",
Babel.instance.config.BABEL_MESSAGE_POT_FILE,
self.babel.config.BABEL_MESSAGE_POT_FILE,
watch_dir,
]
)
Expand All @@ -173,11 +175,11 @@ def init(self, lang: Optional[str] = None) -> None:
BabelCli.__module_name__,
"init",
"-i",
Babel.instance.config.BABEL_MESSAGE_POT_FILE,
self.babel.config.BABEL_MESSAGE_POT_FILE,
"-d",
Babel.instance.config.BABEL_TRANSLATION_DIRECTORY,
self.babel.config.BABEL_TRANSLATION_DIRECTORY,
"-l",
lang or Babel.instance.config.BABEL_DEFAULT_LOCALE,
lang or self.babel.config.BABEL_DEFAULT_LOCALE,
]
)

Expand All @@ -193,9 +195,9 @@ def update(self, watch_dir: Optional[str] = None) -> None:
BabelCli.__module_name__,
"update",
"-i",
Babel.instance.config.BABEL_MESSAGE_POT_FILE,
self.babel.config.BABEL_MESSAGE_POT_FILE,
"-d",
watch_dir or Babel.instance.config.BABEL_TRANSLATION_DIRECTORY,
watch_dir or self.babel.config.BABEL_TRANSLATION_DIRECTORY,
]
)

Expand All @@ -209,7 +211,7 @@ def compile(self):
BabelCli.__module_name__,
"compile",
"-d",
Babel.instance.config.BABEL_TRANSLATION_DIRECTORY,
self.babel.config.BABEL_TRANSLATION_DIRECTORY,
]
)

Expand Down
11 changes: 9 additions & 2 deletions fastapi_babel/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from typing import Optional


class BabelProxyError(Exception):
"""When babel proxy object points to a None object will raise this error"""
def __init__(self, *args: object) -> None:
super().__init__("Proxy object points to an empty lookup instance")

def __init__(self, message: Optional[str] = None) -> None:
self.message: str = "Proxy object points to an empty lookup instance"
if message:
self.message = message
super().__init__("Proxy object points to an empty lookup instance")
57 changes: 36 additions & 21 deletions fastapi_babel/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from starlette.middleware.base import RequestResponseEndpoint
from starlette.middleware.base import DispatchFunction
from starlette.types import ASGIApp
from typing import TYPE_CHECKING, Optional
from typing import Optional
from .core import Babel, _context_var
from .properties import RootConfigs
from pathlib import Path
Expand All @@ -16,11 +16,11 @@

class BabelMiddleware(BaseHTTPMiddleware):
def __init__(
self,
app: ASGIApp,
babel_configs: RootConfigs,
jinja2_templates: Jinja2Templates = None,
dispatch: Optional[DispatchFunction] = None,
self,
app: ASGIApp,
babel_configs: RootConfigs,
jinja2_templates: Optional[Jinja2Templates] = None,
dispatch: Optional[DispatchFunction] = None,
) -> None:
super().__init__(app, dispatch)
self.babel_configs = babel_configs
Expand All @@ -29,40 +29,53 @@ def __init__(
def get_language(self, babel: Babel, lang_code):
"""Applies an available language.
To apply an available language it will be searched in the language folder for an available one
and will also priotize the one with the highest quality value. The Fallback language will be the
taken from the BABEL_DEFAULT_LOCALE var.
To apply an available language it will be searched in the language folder for an available one
and will also priotize the one with the highest quality value. The Fallback language will be the
taken from the BABEL_DEFAULT_LOCALE var.
Args:
babel (Babel): Request scoped Babel instance
lang_code (str): The Value of the Accept-Language Header.
Args:
babel (Babel): Request scoped Babel instance
lang_code (str): The Value of the Accept-Language Header.
Returns:
str: The language that should be used.
Returns:
str: The language that should be used.
"""
if not lang_code:
return babel.config.BABEL_DEFAULT_LOCALE

matches = re.finditer(LANGUAGES_PATTERN, lang_code)
languages = [(f"{m.group(1)}{f'_{m.group(2)}' if m.group(2) else ''}", m.group(3) or "") for m in matches]
languages = sorted(languages, key=lambda x: x[1], reverse=True) # sort the priority, no priority comes last
languages = [
(f"{m.group(1)}{f'_{m.group(2)}' if m.group(2) else ''}", m.group(3) or "")
for m in matches
]
languages = sorted(
languages, key=lambda x: x[1], reverse=True
) # sort the priority, no priority comes last
translation_directory = Path(babel.config.BABEL_TRANSLATION_DIRECTORY)
translation_files = [i.name for i in translation_directory.iterdir()]
explicit_priority = None

for lang, quality in languages:
if lang in translation_files:
if not quality: # languages without quality value having the highest priority 1
if (
not quality
): # languages without quality value having the highest priority 1
return lang

elif not explicit_priority: # set language with explicit priority <= priority 1
elif (
not explicit_priority
): # set language with explicit priority <= priority 1
explicit_priority = lang

# Return language with explicit priority or default value
return explicit_priority if explicit_priority else self.babel_configs.BABEL_DEFAULT_LOCALE
return (
explicit_priority
if explicit_priority
else self.babel_configs.BABEL_DEFAULT_LOCALE
)

async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
"""dispatch function
Expand All @@ -78,7 +91,9 @@ async def dispatch(
# Create a new Babel instance per request
request.state.babel = Babel(configs=self.babel_configs)
request.state.babel.locale = self.get_language(request.state.babel, lang_code)
_context_var.set(request.state.babel.gettext) # Set the _ function in the context variable
_context_var.set(
request.state.babel.gettext
) # Set the _ function in the context variable
if self.jinja2_templates:
request.state.babel.install_jinja(self.jinja2_templates)

Expand Down
2 changes: 1 addition & 1 deletion fastapi_babel/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@dataclass
class RootConfigs:

ROOT_DIR: str
ROOT_DIR: str | pathlib.Path
BABEL_DEFAULT_LOCALE: str
BABEL_TRANSLATION_DIRECTORY: str
BABEL_DOMAIN: str = "messages.pot"
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fastapi
babel
uvicorn
pathlib
uvicorn

0 comments on commit f5badb8

Please sign in to comment.