Skip to content

Instantly share code, notes, and snippets.

@ewjoachim
Last active April 24, 2020 16:22
Show Gist options
  • Save ewjoachim/d55d9b7dc55d8120ede3a38fc6cc6f36 to your computer and use it in GitHub Desktop.
Save ewjoachim/d55d9b7dc55d8120ede3a38fc6cc6f36 to your computer and use it in GitHub Desktop.
Workable gettext
# workalendar/i18n.py
import gettext
import collections
_ = lambda x: x
def get_translation_for_language(language: str) -> gettext.Translations:
return gettext.translation("mydomain", "/path/to/translations", [language])
def gettext(message:str) -> str:
return translations[get_current_language()].gettext(message)
def ngettext(count: int, message: str) -> str:
return translations[get_current_language()].ngettext(count, message)
def pgettext(context: str, message: str) -> str:
# 3.8+ only :o
return translations[get_current_language()].pgettext(context, message)
...
def get_current_language() -> str:
# Do some magic: read a module variable or a threadlocal or a ContextVar or whatever. Your business.
def set_current_translation(language: str) -> None:
# Do some magic: write a module variable or a threadlocal or a ContextVar or whatever. Your business.
# a.k.a translation.activate
@contextlib.contextmanager
def override_language(language: str):
prev = get_current_language()
set_current_language(language)
try:
yield
finally:
set_current_language(prev)
translations = collections.defaultdict(get_translation_for_language)
# workalendar/elsewhere.py
from workalendar.i18n import _, translate
holiday_name = _("Pâques")
def easter_name():
set_current_language("fr")
return gettext(holiday_name)
#also works with
with translation_override("de"):
gettext("Pâques")
# now back to french
# workalendar/i18n.py
import gettext
import collections
_ = lambda x: x
def get_translation_for_language(language: str) -> gettext.Translations:
return gettext.translation("mydomain", "/path/to/translations", [language])
def translate(language: str, message:str) -> str:
return translations[language].gettext(message)
def translate_count(language: str, count: int, message: str) -> str:
return translations[language].ngettext(count, message)
def translate_context(language: str, context: str, message: str) -> str:
# 3.8+ only :o
return translations[language].pgettext(context, message)
translations = collections.defaultdict(get_translation_for_language)
# workalendar/elsewhere.py
from workalendar.i18n import _, translate
holiday_name = _("Pâques")
def easter_name(language):
return translate(language, holiday_name)
# or
return translate(language, _("Pâques"))
@brunobord
Copy link

too bad for the defaultdict function. the function that's passed as a parameter doesn't accept arguments. I've found a way to make my own factory, though.
One step at a time...

@ewjoachim
Copy link
Author

Ah snap what I meant was actually a lru_cache ! If you lru_cache get_translation_for_language, then it would work (and you don't need the translation object anymore)

@brunobord
Copy link

possibly. I think it'd be too early for caching stuff and such. What I'm trying to do at least (with a bit of success, right now, but it's late and I'm tired) is to get translations when language is known. It worked. I'm glad.

Premature optimisation is the root of all evil.

@ewjoachim
Copy link
Author

Hm, I think gettext.translation("mydomain", "/path/to/translations", [language]) is really not meant to be called multiple times...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment