diff --git a/MANIFEST.in b/MANIFEST.in index 2a4d01251..38479bb1f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ recursive-include packtools *.xsd *.sch *.xml *.ent *.dtd *.mod *.xslt *.json *.xsl *.html *.ico *.css *.txt *.png *.js -recursive-include packtools/sps/locale *.mo +recursive-include packtools/sps/locale *.mo *.po recursive-exclude tests * include README.md HISTORY.md exclude tox.ini diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..2578aa6f7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=68", "wheel", "Babel>=2.12"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/setup.py b/setup.py index 3460a8e8f..d72dbe2b3 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,9 @@ #!/usr/bin/env python #coding:utf-8 from __future__ import unicode_literals +from pathlib import Path from setuptools import setup +from setuptools.command.build_py import build_py as _build_py import setuptools import codecs import sys @@ -11,6 +13,34 @@ raise RuntimeError('Requires Python 3.9 or newer') +LOCALE_DIR = Path(__file__).resolve().parent / "packtools" / "sps" / "locale" + + +def compile_sps_i18n_catalogs(): + """Compila packtools/sps/locale/*/LC_MESSAGES/*.po para .mo. + + MANIFEST.in so inclui *.mo (nao *.po) na distribuicao, entao sem esse + passo os catalogos ficam de fora do sdist/wheel e + packtools.sps.i18n.set_locale() nunca encontra traducao nenhuma - ver + issue #1267. + """ + from babel.messages.mofile import write_mo + from babel.messages.pofile import read_po + + for po_path in sorted(LOCALE_DIR.glob("*/LC_MESSAGES/*.po")): + with po_path.open("rb") as po_file: + catalog = read_po(po_file) + mo_path = po_path.with_suffix(".mo") + with mo_path.open("wb") as mo_file: + write_mo(mo_file, catalog) + + +class build_py(_build_py): + def run(self): + compile_sps_i18n_catalogs() + super().run() + + # adds version to the local namespace VERSION = {} with open('packtools/version.py') as fp: @@ -67,6 +97,7 @@ exclude=["*.tests", "*.tests.*", "tests.*", "tests", "docs"] ), include_package_data=True, + cmdclass={"build_py": build_py}, classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", diff --git a/tests/sps/test_i18n_packaging.py b/tests/sps/test_i18n_packaging.py new file mode 100644 index 000000000..8d0ea21c6 --- /dev/null +++ b/tests/sps/test_i18n_packaging.py @@ -0,0 +1,96 @@ +import shutil +import subprocess +import sys +import tempfile +import unittest +import venv +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] + +KNOWN_MSGID = "Got {obtained}, expected {expected}" + + +class BuildIncludesI18nCatalogsTest(unittest.TestCase): + """Constroi o wheel do packtools e instala num venv limpo, reproduzindo + os passos da issue #1267, pra garantir que os catalogos i18n de + packtools/sps sao empacotados de verdade (nao so presentes no + checkout do git) e que set_locale() funciona de ponta a ponta. + """ + + @classmethod + def setUpClass(cls): + cls.tmp_dir = Path(tempfile.mkdtemp(prefix="packtools_build_test_")) + + wheel_dir = cls.tmp_dir / "wheel" + wheel_dir.mkdir() + subprocess.run( + [ + sys.executable, + "-m", + "pip", + "wheel", + str(REPO_ROOT), + "--no-deps", + "-w", + str(wheel_dir), + ], + check=True, + capture_output=True, + ) + wheels = list(wheel_dir.glob("packtools-*.whl")) + assert len(wheels) == 1, f"esperava 1 wheel, encontrou {wheels}" + cls.wheel_path = wheels[0] + + venv_dir = cls.tmp_dir / "venv" + venv.EnvBuilder(with_pip=True).create(venv_dir) + cls.venv_python = venv_dir / "bin" / "python" + subprocess.run( + [str(cls.venv_python), "-m", "pip", "install", "--quiet", str(cls.wheel_path)], + check=True, + capture_output=True, + ) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.tmp_dir, ignore_errors=True) + + def _run_in_clean_venv(self, code): + result = subprocess.run( + [str(self.venv_python), "-c", code], + check=True, + capture_output=True, + text=True, + ) + return result.stdout.strip() + + def test_locale_dir_is_installed(self): + output = self._run_in_clean_venv( + "from packtools.sps import i18n; print(i18n.LOCALE_DIR.exists())" + ) + self.assertEqual(output, "True") + + def test_set_locale_pt_br_translates_known_message(self): + output = self._run_in_clean_venv( + "from packtools.sps import i18n; " + f"i18n.set_locale('pt_BR'); print(i18n._({KNOWN_MSGID!r}))" + ) + self.assertEqual(output, "Obtido {obtained}, esperado {expected}") + + def test_set_locale_es_translates_known_message(self): + output = self._run_in_clean_venv( + "from packtools.sps import i18n; " + f"i18n.set_locale('es'); print(i18n._({KNOWN_MSGID!r}))" + ) + self.assertEqual(output, "Se obtuvo {obtained}, se esperaba {expected}") + + def test_set_locale_en_keeps_source_message(self): + output = self._run_in_clean_venv( + "from packtools.sps import i18n; " + f"i18n.set_locale('en'); print(i18n._({KNOWN_MSGID!r}))" + ) + self.assertEqual(output, KNOWN_MSGID) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file