Source code for iamai.i18n

import os
import polib
import gettext
import subprocess


from iamai.const import __version__
from typing import List
from gettext import GNUTranslations

localedir = os.path.join(os.path.dirname(__file__), "locale")


[docs] def setup_gettext( domain: str = "i18n", localedir: str = localedir, languages: List[str] = ["en"], ) -> GNUTranslations: """Setup gettext Args: domain (str, optional): Defaults to `os.path.basename(__file__).strip(".py")`. localedir (str, optional): Defaults to `localedir`. languages (List[str], optional): Defaults to `["en"]`. Returns: GNUTranslations: The translation object """ try: # Try to bind the specified domain compile_mo_files(localedir, domain) translation = gettext.translation(domain, localedir, languages=languages) except FileNotFoundError: # Fallback to the default domain 'messages' if the specified domain is not found _domain = "i18n" compile_mo_files(localedir, _domain) translation = gettext.translation( _domain, localedir, languages=languages, fallback=True ) # Install the translation object globally translation.install() return translation.gettext
[docs] def compile_mo_files(localedir: str, domain: str) -> None: """Compile .po files to .mo files Args: localedir (str): locale directory domain (str): locale domain """ for lang in os.listdir(localedir): po_path = os.path.join(localedir, lang, "LC_MESSAGES", f"{domain}.po") mo_path = os.path.join(localedir, lang, "LC_MESSAGES", f"{domain}.mo") if os.path.exists(po_path): # Compile if .mo file doesn't exist or is older than the .po file if not os.path.exists(mo_path) or os.path.getmtime( po_path ) > os.path.getmtime(mo_path): po = polib.pofile(po_path) po.save_as_mofile(mo_path)
[docs] class TranslationManager: def __init__(self, src_dir="iamai", locale_dir="locale", pot_file="i18n.pot"): self.src_dir = src_dir self.locale_dir = locale_dir self.pot_file = pot_file
[docs] def generate_pot(self): py_files = self._find_python_files() pot_path = os.path.join(self.src_dir, self.locale_dir, self.pot_file) os.makedirs(os.path.dirname(pot_path), exist_ok=True) print("Generating POT file...") subprocess.run( ["xgettext", "-o", pot_path, "--language=Python", "--keyword=_"] + py_files )
[docs] def generate_po(self, languages=None): if languages is None: languages = ["zh"] self.generate_pot() for lang in languages: po_dir = os.path.join(self.src_dir, self.locale_dir, lang, "LC_MESSAGES") po_file = os.path.join(po_dir, "i18n.po") os.makedirs(po_dir, exist_ok=True) if not os.path.isfile(po_file): print(f"Generating PO file for language {lang}...") subprocess.run( [ "msginit", "--locale", lang, "--input", os.path.join(self.src_dir, self.locale_dir, self.pot_file), "--output-file", po_file, "--no-translator", ] ) self._set_utf8_encoding(po_file) else: print( f"PO file for language {lang} already exists, skipping generation." )
[docs] def update_po(self): self.generate_pot() po_files = self._find_po_files() for po_file in po_files: print(f"Updating {po_file}...") subprocess.run( [ "msgmerge", "--update", po_file, os.path.join(self.src_dir, self.locale_dir, self.pot_file), ] )
[docs] def compile_mo(self): po_files = self._find_po_files() for po_file in po_files: mo_file = po_file.replace(".po", ".mo") print(f"Compiling {po_file} to {mo_file}...") subprocess.run(["msgfmt", "-o", mo_file, po_file])
[docs] def clean(self): print("Cleaning up translation files...") pot_path = os.path.join(self.src_dir, self.locale_dir, self.pot_file) if os.path.exists(pot_path): os.remove(pot_path) po_files = self._find_po_files() for po_file in po_files: os.remove(po_file)
def _find_python_files(self): return [ os.path.join(dp, f) for dp, dn, filenames in os.walk(self.src_dir) for f in filenames if f.endswith(".py") ] def _find_po_files(self): return [ os.path.join(dp, f) for dp, dn, filenames in os.walk(self.src_dir) for f in filenames if f == "i18n.po" ] def _set_utf8_encoding(self, po_file): with open(po_file, "r+", encoding="utf-8") as file: content = file.read() content = content.replace("charset=ASCII", "charset=UTF-8") file.seek(0) file.write(content) file.truncate()
if __name__ == "__main__": _ = setup_gettext(languages=["zh"]) print(_("Version: {version}").format(version=__version__)) manager = TranslationManager() manager.generate_po(languages=["fr", "es"]) manager.update_po() manager.compile_mo() manager.clean()