Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize python versions #39

Merged
merged 8 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:

strategy:
matrix:
python: ["2.7", "3.6", "3.7", "3.8"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]
tseaver marked this conversation as resolved.
Show resolved Hide resolved

name: Test Python ${{ matrix.python }}

Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: 3.7
python-version: 3.12

- name: Install wheel
run: python -m pip install wheel --user
Expand Down
11 changes: 11 additions & 0 deletions changes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
translationstring
=================

2.0 (unreleased)
----------------

- Add support for Python 3.8 - 3.13.

- Drop support for Python 2.7 and Python 3 < 3.8 (this release now adds
``python_requires='>=3.8'``, so that older Python versions won't install
it.

- Remove ``translationstring.compat`` module.

1.4 (2020-07-09)
----------------

Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# out serve to show the default value.

import sys, os, datetime
import pkg_resources
from importlib import metadata
import pylons_sphinx_themes

# General configuration
Expand Down Expand Up @@ -41,7 +41,7 @@
# other places throughout the built documents.
#
# The short X.Y version.
version = pkg_resources.get_distribution('translationstring').version
version = metadata.version('translationstring')
# The full version, including alpha/beta/rc tags.
release = version

Expand Down
8 changes: 7 additions & 1 deletion docs/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ Glossary
predefines a :term:`translation domain`.

Translation Domain
A string representing the "context" in which a particular
A string representing the "domain" in which a particular
translation was made. For example the word "java" might be
translated differently if the translation domain is
"programming-languages" than would be if the translation domain
was "coffee". Every :term:`translation string` has an associated
tseaver marked this conversation as resolved.
Show resolved Hide resolved
translation domain.

Translation Context
An optional string added to help resolve translation ambiguities
associated with very short terms, such as those which appear in
GUI menus, etc. See:
https://www.gnu.org/software/gettext/manual/gettext.html#Contexts

Message Identifier
An unchanging string that is the identifier for a particular
translation string. For example, you may have a translation
Expand Down
20 changes: 15 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
'pylons-sphinx-themes',
]

testing_extras = [
'pytest',
'pytest-cov',
'coverage'
]

setup(
name='translationstring',
version='1.4dev',
Expand All @@ -27,19 +33,21 @@
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Internationalization",
"Topic :: Software Development :: Localization",
"License :: Repoze Public License",
],
python_requires='>=3.8',
keywords='i18n l10n internationalization localization gettext chameleon',
author="Chris McDonough, Agendaless Consulting",
author_email="[email protected]",
Expand All @@ -50,6 +58,8 @@
zip_safe=False,
test_suite="translationstring",
extras_require={
'test': testing_extras,
'testing': testing_extras,
'docs': docs_extras,
},
)
15 changes: 7 additions & 8 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
[tox]
envlist =
py27,py33,py34,py35,pypy,cover,docs
py38,py39,py310,py311,py312,py313,pypy3,cover,docs

[testenv]
commands =
python setup.py test -q
pytest
deps =
pytest
Babel

[testenv:cover]
basepython =
python2.7
python3.12
commands =
python setup.py nosetests --with-xunit --with-xcoverage
pytest --cov=translationstring
deps =
Babel
nose
coverage==3.4
nosexcover
pytest-cov

[testenv:docs]
basepython =
python2.7
python3.12
commands =
pip install translationstring[docs]
sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
Expand Down
63 changes: 29 additions & 34 deletions translationstring/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import re
from gettext import NullTranslations
from translationstring.compat import text_type
from translationstring.compat import string_types
from translationstring.compat import PY3

NAME_RE = r"[a-zA-Z][-a-zA-Z0-9_]*"

_interp_regex = re.compile(r'(?<!\$)(\$(?:(%(n)s)|{(%(n)s)}))'
% ({'n': NAME_RE}))

CONTEXT_MASK = text_type('%s\x04%s')
CONTEXT_MASK = u'%s\x04%s'
tseaver marked this conversation as resolved.
Show resolved Hide resolved

class TranslationString(text_type):
class TranslationString(str):
"""
The constructor for a :term:`translation string`. A translation
string is a Unicode-like object that has some extra metadata.
Expand Down Expand Up @@ -63,13 +60,15 @@ class TranslationString(text_type):
"""
__slots__ = ('domain', 'context', 'default', 'mapping')

def __new__(self, msgid, domain=None, default=None, mapping=None, context=None):
def __new__(
self, msgid, domain=None, default=None, mapping=None, context=None
):

# NB: this function should never never lose the *original
# identity* of a non-``None`` but empty ``default`` value
# provided to it. See the comment in ChameleonTranslate.

self = text_type.__new__(self, msgid)
self = str.__new__(self, msgid)
if isinstance(msgid, self.__class__):
domain = domain or msgid.domain and msgid.domain[:]
context = context or msgid.context and msgid.context[:]
Expand All @@ -80,11 +79,11 @@ def __new__(self, msgid, domain=None, default=None, mapping=None, context=None):
mapping.setdefault(k, v)
else:
mapping = msgid.mapping.copy()
msgid = text_type(msgid)
msgid = str(msgid)
self.domain = domain
self.context = context
if default is None:
default = text_type(msgid)
default = str(msgid)
self.default = default
self.mapping = mapping
return self
Expand Down Expand Up @@ -129,7 +128,7 @@ def interpolate(self, translated=None):
if self.mapping and translated:
def replace(match):
whole, param1, param2 = match.groups()
return text_type(self.mapping.get(param1 or param2, whole))
return str(self.mapping.get(param1 or param2, whole))
translated = _interp_regex.sub(replace, translated)

return translated
Expand All @@ -138,7 +137,7 @@ def __reduce__(self):
return self.__class__, self.__getstate__()

def __getstate__(self):
return text_type(self), self.domain, self.default, self.mapping, self.context
return str(self), self.domain, self.default, self.mapping, self.context

def TranslationStringFactory(factory_domain):
""" Create a factory which will generate translation strings
Expand Down Expand Up @@ -214,15 +213,17 @@ def translate(msgid, domain=None, mapping=None, context=None,
# preserving ``default`` in the aforementioned case. So we
# spray these indignant comments all over this module. ;-)

if not isinstance(msgid, string_types):
if not isinstance(msgid, str):
if msgid is not None:
msgid = text_type(msgid)
msgid = str(msgid)
return msgid

tstring = msgid

if not hasattr(tstring, 'interpolate'):
tstring = TranslationString(msgid, domain, default, mapping, context)
tstring = TranslationString(
msgid, domain, default, mapping, context
)
if translator is None:
result = tstring.interpolate()
else:
Expand All @@ -236,10 +237,7 @@ def ugettext_policy(translations, tstring, domain, context):
""" A translator policy function which unconditionally uses the
``ugettext`` API on the translations object."""

if PY3: # pragma: no cover
_gettext = translations.gettext
else: # pragma: no cover
_gettext = translations.ugettext
_gettext = translations.gettext

if context:
# Workaround for http://bugs.python.org/issue2504?
Expand Down Expand Up @@ -267,10 +265,7 @@ def dugettext_policy(translations, tstring, domain, context):
if getattr(translations, 'dugettext', None) is not None:
translated = translations.dugettext(domain, msgid)
else:
if PY3: # pragma: no cover
_gettext = translations.gettext
else: # pragma: no cover
_gettext = translations.ugettext
_gettext = translations.gettext

translated = _gettext(msgid)
return tstring if translated == msgid else translated
Expand Down Expand Up @@ -305,14 +300,18 @@ def Translator(translations=None, policy=None):
policy = dugettext_policy
def translator(tstring, domain=None, mapping=None, context=None):
if not hasattr(tstring, 'interpolate'):
tstring = TranslationString(tstring, domain=domain, mapping=mapping, context=context)
tstring = TranslationString(
tstring, domain=domain, mapping=mapping, context=context
)
elif mapping:
if tstring.mapping:
new_mapping = tstring.mapping.copy()
new_mapping.update(mapping)
else:
new_mapping = mapping
tstring = TranslationString(tstring, domain=domain, mapping=new_mapping, context=context)
tstring = TranslationString(
tstring, domain=domain, mapping=new_mapping, context=context
)
translated = tstring
domain = domain or tstring.domain
context = context or tstring.context
Expand All @@ -329,10 +328,7 @@ def ungettext_policy(translations, singular, plural, n, domain, context):
""" A pluralizer policy function which unconditionally uses the
``ungettext`` API on the translations object."""

if PY3: # pragma: no cover
_gettext = translations.ngettext
else: # pragma: no cover
_gettext = translations.ungettext
_gettext = translations.ngettext

if context:
# Workaround for http://bugs.python.org/issue2504?
Expand All @@ -358,10 +354,7 @@ def dungettext_policy(translations, singular, plural, n, domain, context):
if getattr(translations, 'dungettext', None) is not None:
translated = translations.dungettext(domain, msgid, plural, n)
else:
if PY3: # pragma: no cover
_gettext = translations.ngettext
else: # pragma: no cover
_gettext = translations.ungettext
_gettext = translations.ngettext

translated = _gettext(msgid, plural, n)
return singular if translated == msgid else translated
Expand Down Expand Up @@ -400,9 +393,11 @@ def pluralizer(singular, plural, n, domain=None, mapping=None):
policy = dungettext_policy
if translations is None:
translations = NullTranslations()
def pluralizer(singular, plural, n, domain=None, mapping=None, context=None):
def pluralizer(
singular, plural, n, domain=None, mapping=None, context=None
):
""" Pluralize this object """
translated = text_type(
translated = str(
policy(translations, singular, plural, n, domain, context))
if translated and '$' in translated and mapping:
return TranslationString(translated, mapping=mapping).interpolate()
Expand Down
18 changes: 0 additions & 18 deletions translationstring/compat.py

This file was deleted.

Loading
Loading