jamtur01's picture
Upload folder using huggingface_hub
9c6594c verified
from __future__ import annotations
import re
import warnings
from typing import Any
class I18nData:
"""
A class that wraps a translation key with metadata.
This object will be serialized and sent to the frontend, where the actual
translation will happen using the frontend's i18n system.
"""
def __init__(self, key: str):
"""
Initialize a I18nData object.
Args:
key: The translation key to be translated in the frontend.
"""
self.key = key
self._type = "translation_metadata"
def to_dict(self) -> dict[str, Any]:
"""
Convert the I18nData object to a dictionary for serialization.
This allows the frontend to recognize it as a translatable object.
"""
return {"__type__": self._type, "key": self.key}
def __str__(self) -> str:
"""
String representation of the I18nData object.
Used when the object is converted to a string.
This returns a special format that can be recognized by the frontend
as needing translation.
"""
import json
return f"__i18n__{json.dumps(self.to_dict())}"
def __repr__(self) -> str:
"""
Representation of the I18nData object for debugging.
"""
return self.__str__()
def __add__(self, other):
"""
Handle string concatenation (self + other).
"""
return str(self) + str(other)
def __radd__(self, other):
"""
Handle string concatenation (other + self).
"""
return str(other) + str(self)
def __getattr__(self, name):
"""
Handle attribute access for I18nData.
This makes it possible to use I18nData objects in contexts
that expect strings with methods.
"""
if name.startswith("__") and name.endswith("__"):
raise AttributeError(f"{self.__class__.__name__} has no attribute {name}")
def method(*_args, **_kwargs):
return self
return method
def tojson(self) -> dict[str, Any]:
"""
Convert the I18nData object to a JSON-serializable dictionary.
This is used by the default Python JSON serializer.
"""
return self.to_dict()
class I18n:
"""
Handles internationalization (i18n) for Gradio applications.
Stores translation dictionaries and provides a method to retrieve translation keys.
The translation lookup happens on the frontend based on the browser's locale
and the provided translation dictionaries.
"""
# BCP 47 language tag regex pattern
_LOCALE_PATTERN = re.compile(r"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$")
def __init__(self, **translations: dict[str, str]):
"""
Initializes the I18n class.
Args:
**translations: Each keyword argument should be a locale code (e.g., "en", "fr") with a
dictionary value, which maps translation keys to translated strings.
Example: gr.I18n(en={"greeting": "Hello"}, es={"greeting": "Hola"})
These translations can be passed to the frontend for use there.
"""
self.translations = {}
for locale, translation_dict in translations.items():
if not self._is_valid_locale(locale):
warnings.warn(
f"Invalid locale code: '{locale}'. Locale codes should follow BCP 47 format (e.g., 'en', 'en-US'). "
f"This locale will still be included, but may not work correctly.",
UserWarning,
)
self.translations[locale] = translation_dict
def _is_valid_locale(self, locale: str) -> bool:
return bool(self._LOCALE_PATTERN.match(locale))
def __call__(self, key: str) -> I18nData:
"""
Returns a I18nData object containing the translation key.
This metadata object will be serialized and sent to the frontend,
where it will be translated by the frontend's i18n system.
Args:
key: The key to identify the translation string (e.g., "submit_button").
Returns:
A I18nData object containing the translation key.
"""
return I18nData(key)
@property
def translations_dict(self) -> dict[str, dict[str, str]]:
"""
Returns the dictionary of translations provided during initialization.
These can be passed to the frontend for use in its translation system.
"""
return self.translations