aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-02-11 16:51:44 +0100
committerWojtek Kosior <koszko@koszko.org>2022-02-12 11:34:59 +0100
commit9e71d383bf59573a1dd48964a2c7900a57161973 (patch)
tree8d4f2013815836ae4665825809b1f3bf8e9c4b77
parent4e46d7f7446b66e7f128169bb15b9cc88b03b3ba (diff)
downloadhydrilla-builder-9e71d383bf59573a1dd48964a2c7900a57161973.tar.gz
hydrilla-builder-9e71d383bf59573a1dd48964a2c7900a57161973.zip
internationalize using Babel
this commit also makes the sdist tarball generated by setuptools REUSE-compliant
-rw-r--r--.gitignore2
-rw-r--r--.reuse/dep512
-rw-r--r--MANIFEST.in1
-rw-r--r--pyproject.toml2
-rw-r--r--setup.cfg30
-rwxr-xr-xsetup.py12
-rw-r--r--src/hydrilla/builder/__main__.py51
-rw-r--r--src/hydrilla/builder/build.py31
-rw-r--r--src/hydrilla/locales/en_US/LC_MESSAGES/hydrilla_builder.po67
-rw-r--r--src/hydrilla/util/__init__.py2
-rw-r--r--src/hydrilla/util/_util.py30
11 files changed, 178 insertions, 62 deletions
diff --git a/.gitignore b/.gitignore
index a5df35a..1d50e8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ dist
*.pyc
setuptools
src/hydrilla/builder/_version.py
+src/hydrilla/locales/hydrilla_builder.pot
+hydrilla_builder.mo \ No newline at end of file
diff --git a/.reuse/dep5 b/.reuse/dep5
index 9cf1093..7cd5158 100644
--- a/.reuse/dep5
+++ b/.reuse/dep5
@@ -3,8 +3,10 @@ Upstream-Name: Hydrilla builder
Upstream-Contact: Wojtek Kosior <koszko@koszko.org>
Source: https://git.koszko.org/hydrilla-builder
-# Sample paragraph, commented out:
-#
-# Files: src/*
-# Copyright: $YEAR $NAME <$CONTACT>
-# License: ...
+Files: PKG-INFO setup.cfg src/hydrilla/builder/_version.py
+ src/hydrilla.builder.egg-info/*
+Copyright: 2022 Wojtek Kosior <koszko@koszko.org>
+License: CC0-1.0
+Comment: Those are files that setuptools generate in sdist.
+ `setup.cfg` gets stripped of comments during generation of
+ sdist, so we include it here as well.
diff --git a/MANIFEST.in b/MANIFEST.in
index 7b65971..133611e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -5,5 +5,6 @@
# Available under the terms of Creative Commons Zero v1.0 Universal.
include src/hydrilla/schemas/*.schema.json*
+include src/hydrilla/locales/*/LC_MESSAGES/hydrilla_builder.po
include src/test/source-package-example/*
global-exclude .git .gitignore .gitmodules
diff --git a/pyproject.toml b/pyproject.toml
index a41a6ec..cffd3dd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@
[build-system]
build-backend = "setuptools.build_meta"
-requires = ["setuptools>=45", "wheel", "setuptools_scm>=5.0"]
+requires = ["setuptools>=45", "wheel", "setuptools_scm>=5.0", "babel"]
[tool.setuptools_scm]
write_to = "src/hydrilla/builder/_version.py"
diff --git a/setup.cfg b/setup.cfg
index b949fb6..78e384b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -35,10 +35,12 @@ include_package_data=True
install_requires =
click
jsonschema
- importlib; python_version == "2.6"
# reuse is optional:
# reuse
+[options.package_data]
+* = *.mo
+
[options.extras_require]
test = pytest
setup = setuptools_scm
@@ -50,4 +52,28 @@ exclude =
[options.entry_points]
console_scripts =
- hydrilla-builder = hydrilla.builder.__main__:perform_build
+ hydrilla-builder = hydrilla.builder.build:perform
+
+[extract_messages]
+keywords = _
+width = 80
+input_dirs = src/hydrilla
+output_file = src/hydrilla/locales/hydrilla_builder.pot
+msgid_bugs_address = koszko@koszko.org
+sort_by_file = True
+copyright_holder = Wojtek Kosior <koszko@koszko.org>
+
+[init_catalog]
+input_file = src/hydrilla/locales/hydrilla_builder.pot
+output_dir = src/hydrilla/locales/
+domain = hydrilla_builder
+
+[update_catalog]
+input_file = src/hydrilla/locales/hydrilla_builder.pot
+output_dir = src/hydrilla/locales/
+domain = hydrilla_builder
+
+[compile_catalog]
+directory = src/hydrilla/locales
+use_fuzzy = True
+domain = hydrilla_builder
diff --git a/setup.py b/setup.py
index 6554e08..345febc 100755
--- a/setup.py
+++ b/setup.py
@@ -7,4 +7,14 @@
import setuptools
-setuptools.setup()
+from setuptools.command.build_py import build_py
+
+class CustomBuildCommand(build_py):
+ '''
+ The build command but runs babel before build.
+ '''
+ def run(self, *args, **kwargs):
+ self.run_command('compile_catalog')
+ super().run(*args, **kwargs)
+
+setuptools.setup(cmdclass={'build_py': CustomBuildCommand})
diff --git a/src/hydrilla/builder/__main__.py b/src/hydrilla/builder/__main__.py
index e60c50d..87dc9e2 100644
--- a/src/hydrilla/builder/__main__.py
+++ b/src/hydrilla/builder/__main__.py
@@ -1,50 +1,9 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
+# SPDX-License-Identifier: CC0-1.0
-# Command line interface of Hydrilla package builder.
+# Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
#
-# This file is part of Hydrilla
-#
-# Copyright (C) 2022 Wojtek Kosior
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-#
-# I, Wojtek Kosior, thereby promise not to sue for violation of this
-# file's license. Although I request that you do not make use this code
-# in a proprietary program, I am not going to enforce this in court.
-
-from pathlib import Path
-
-import click
-
-from .build import Build
-
-dir_type = click.Path(exists=True, file_okay=False, resolve_path=True)
+# Available under the terms of Creative Commons Zero v1.0 Universal.
-@click.command()
-@click.option('-s', '--srcdir', default='./', type=dir_type, show_default=True,
- help='Source directory to build from.')
-@click.option('-i', '--index-json', default='index.json', type=click.Path(),
- help='Path to file to be processed instead of index.json (if not absolute, resolved relative to srcdir).')
-@click.option('-d', '--dstdir', type=dir_type, required=True,
- help='Destination directory to write built package files to.')
-def preform_build(srcdir, index_json, dstdir):
- """
- Build Hydrilla package from scrdir and write the resulting files under
- dstdir.
- """
- build = Build(Path(srcdir), Path(index_json))
- build.write_package_files(Path(dstdir))
+from . import build
-preform_build()
+build.perform()
diff --git a/src/hydrilla/builder/build.py b/src/hydrilla/builder/build.py
index cdbfad3..8d25b19 100644
--- a/src/hydrilla/builder/build.py
+++ b/src/hydrilla/builder/build.py
@@ -32,9 +32,12 @@ from hashlib import sha256
from sys import stderr
import jsonschema
+import click
from .. import util
+_ = util.get_gettext('hydrilla_builder')
+
index_validator = util.validator_for('package_source-1.schema.json')
class FileReferenceError(Exception):
@@ -99,12 +102,12 @@ def generate_spdx_report(root):
try:
from reuse._main import main as reuse_main
except ModuleNotFoundError:
- ReuseError("Could not import 'reuse'. Is the tool installed and visible to this Python instance?")
+ ReuseError(_('couldnt_import_reuse_is_it_installed'))
mocked_output = FileBuffer()
if reuse_main(args=['--root', str(root), 'lint'], out=mocked_output) != 0:
stderr.write(mocked_output.get_bytes().decode())
- raise ReuseError('Attempt to generate an SPDX report for a REUSE-incompliant package.')
+ raise ReuseError(_('spdx_report_from_reuse_incompliant'))
mocked_output = FileBuffer()
if reuse_main(args=['--root', str(root), 'spdx'], out=mocked_output) != 0:
@@ -188,10 +191,11 @@ class Build:
path = path.resolve()
if not path.is_relative_to(self.srcdir):
- raise FileReferenceError(f"Attempt to load '{filename}' which lies outside package source directory.")
+ raise FileReferenceError(_('loading_{}_outside_package_dir')
+ .format(filename))
if str(path.relative_to(self.srcdir)) == 'index.json':
- raise FileReferenceError("Attempt to load 'index.json' which is a reserved filename.")
+ raise FileReferenceError(_('loading_reserved_index_json'))
file_ref = self.files_by_path.get(path)
if file_ref is None:
@@ -305,7 +309,7 @@ class Build:
[self._process_file(f['file']) for f in index_obj['copyright']]
if generate_spdx and not spdx_ref.include_in_distribution:
- raise FileReferenceError("Told to generate 'report.spdx' but 'report.spdx' is not listed among copyright files. Refusing to proceed.")
+ raise FileReferenceError(_('report_spdx_not_in_copyright_list'))
item_refs = [self._process_item(d) for d in index_obj['definitions']]
@@ -373,3 +377,20 @@ class Build:
version = '.'.join([str(n) for n in item_def['version']])
with open(item_dir_path / version, 'wt') as output:
json.dump(item_def, output)
+
+dir_type = click.Path(exists=True, file_okay=False, resolve_path=True)
+
+@click.option('-s', '--srcdir', default='./', type=dir_type, show_default=True,
+ help=_('source_directory_to_build_from'))
+@click.option('-i', '--index-json', default='index.json', type=click.Path(),
+ help=_('path_instead_of_index_json'))
+@click.option('-d', '--dstdir', type=dir_type, required=True,
+ help=_('built_package_files_destination'))
+def perform(srcdir, index_json, dstdir):
+ """<this will be replaced by a localized docstring for Click to pick up>"""
+ build = Build(Path(srcdir), Path(index_json))
+ build.write_package_files(Path(dstdir))
+
+perform.__doc__ = _('build_package_from_srcdir_to_dstdir')
+
+perform = click.command()(perform)
diff --git a/src/hydrilla/locales/en_US/LC_MESSAGES/hydrilla_builder.po b/src/hydrilla/locales/en_US/LC_MESSAGES/hydrilla_builder.po
new file mode 100644
index 0000000..2d351d6
--- /dev/null
+++ b/src/hydrilla/locales/en_US/LC_MESSAGES/hydrilla_builder.po
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: CC0-1.0
+#
+# English (United States) translations for hydrilla.builder.
+# Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
+# Available under the terms of Creative Commons Zero v1.0 Universal.
+msgid ""
+msgstr ""
+"Project-Id-Version: hydrilla.builder 0.1.dev16+g4e46d7f.d20220211\n"
+"Report-Msgid-Bugs-To: koszko@koszko.org\n"
+"POT-Creation-Date: 2022-02-12 10:49+0100\n"
+"PO-Revision-Date: 2022-02-12\n"
+"Last-Translator: Wojtek Kosior <koszko@koszko.org>\n"
+"Language: en_US\n"
+"Language-Team: en_US <koszko@koszko.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.8.0\n"
+
+#: src/hydrilla/builder/build.py:105
+msgid "couldnt_import_reuse_is_it_installed"
+msgstr ""
+"Could not import 'reuse'. Is the tool installed and visible to this "
+"Python instance?"
+
+#: src/hydrilla/builder/build.py:110
+msgid "spdx_report_from_reuse_incompliant"
+msgstr "Attempt to generate an SPDX report for a REUSE-incompliant package."
+
+#: src/hydrilla/builder/build.py:194
+msgid "loading_{}_outside_package_dir"
+msgstr "Attempt to load '{}' which lies outside package source directory."
+
+#: src/hydrilla/builder/build.py:198
+msgid "loading_reserved_index_json"
+msgstr "Attempt to load 'index.json' which is a reserved filename."
+
+#: src/hydrilla/builder/build.py:312
+msgid "report_spdx_not_in_copyright_list"
+msgstr ""
+"Told to generate 'report.spdx' but 'report.spdx' is not listed among "
+"copyright files. Refusing to proceed."
+
+#: src/hydrilla/builder/build.py:384
+msgid "source_directory_to_build_from"
+msgstr "Source directory to build from."
+
+#: src/hydrilla/builder/build.py:386
+msgid "path_instead_of_index_json"
+msgstr ""
+"Path to file to be processed instead of index.json (if not absolute, "
+"resolved relative to srcdir)."
+
+#: src/hydrilla/builder/build.py:388
+msgid "built_package_files_destination"
+msgstr "Destination directory to write built package files to."
+
+#: src/hydrilla/builder/build.py:394
+msgid "build_package_from_srcdir_to_dstdir"
+msgstr ""
+"Build Hydrilla package from `scrdir` and write the resulting files "
+"under `dstdir`."
+
+#: src/hydrilla/util/_util.py:76
+msgid "bad_comment"
+msgstr "bad comment"
diff --git a/src/hydrilla/util/__init__.py b/src/hydrilla/util/__init__.py
index 2a69e0d..3a13831 100644
--- a/src/hydrilla/util/__init__.py
+++ b/src/hydrilla/util/__init__.py
@@ -5,4 +5,4 @@
# Available under the terms of Creative Commons Zero v1.0 Universal.
from ._util import strip_json_comments, normalize_version, parse_version, \
- version_string, validator_for
+ version_string, validator_for, get_gettext
diff --git a/src/hydrilla/util/_util.py b/src/hydrilla/util/_util.py
index 9bebdc1..c7e9f47 100644
--- a/src/hydrilla/util/_util.py
+++ b/src/hydrilla/util/_util.py
@@ -26,6 +26,8 @@
import re
import json
+import locale
+import gettext
from pathlib import Path
from typing import Optional
@@ -71,7 +73,7 @@ def strip_json_comments(text: str) -> str:
# ignore this error, let json module report it
stripped = line
elif len(match[2]) == 1:
- raise json.JSONDecodeError('bad comment', text,
+ raise json.JSONDecodeError(_('bad_comment'), text,
processed + len(match[1]))
else:
stripped = match[1]
@@ -127,3 +129,29 @@ def validator_for(schema_filename: str) -> Draft7Validator:
"""
return Draft7Validator(resolver.resolve(schema_filename)[1],
resolver=resolver)
+
+def get_gettext(domain: str, lang: Optional[str]=None):
+ """
+ Configure translation and return its gettext() function.
+
+ If `lang` is set, look for translations for `lang`. Otherwise, try to
+ determine system's default language and use that.
+ """
+ # https://stackoverflow.com/questions/3425294/how-to-detect-the-os-default-language-in-python
+ # But I am not going to surrender to Microbugs' nonfree, crappy OS to test
+ # it, to the lines inside try: may fail.
+ try:
+ from ctypes.windll import kernel32 as windll
+ lang = locale.windows_locale[windll.GetUserDefaultUILanguage()]
+ except:
+ lang = locale.getdefaultlocale()[0] or 'C'
+
+ translation = gettext.translation(
+ domain,
+ localedir=(here.parent / 'locales'),
+ languages=[lang, 'en_US']
+ )
+
+ return translation.gettext
+
+_ = get_gettext('hydrilla_builder')