mirror of
https://github.com/Hopiu/django-rosetta.git
synced 2026-03-16 21:30:24 +00:00
Merge branch 'develop' of github.com:mbi/django-rosetta into develop
This commit is contained in:
commit
14e9f44901
19 changed files with 103 additions and 77 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -9,7 +9,7 @@ jobs:
|
|||
strategy:
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
python-version: [3.8, 3.9, "3.10"]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
|
|
|||
15
CHANGES
15
CHANGES
|
|
@ -1,14 +1,23 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
Version 0.9.9 (unreleased)
|
||||
--------------------------
|
||||
Version 0.10.0
|
||||
--------------
|
||||
* Fix link to polib. (#277, thanks @gamboz)
|
||||
* Deepl: use the PRO API endpoint when using a PRO API key. (#278, thanks @nullcode)
|
||||
* Limit supported versions to Django 4.2 and 5.0, using Python 3.9, 3.10, 3.11 and 3.12
|
||||
|
||||
|
||||
Version 0.9.9
|
||||
-------------
|
||||
* Use packaged jQuery instead of the CDN version. (#274, thanks @stephanema1)
|
||||
* Test test_47_azure_ajax_translation: avoid DNS lookup for better isolation. Should fix #233
|
||||
* Adds Chinese (Simplified) translation. (#266 thanks @chenluyong)
|
||||
* Test against Django 4.1a
|
||||
* Test against Django 4.1 and 4.2
|
||||
* Limit supported versions to Django 3.2 and later, using Python 3.8, 3.9 and 3.10
|
||||
* Proxy Deepl translations suggestions through the back-end to avoid CORS issues. (#271 thanks @rafaelromon, @biermeester and @matthiask)
|
||||
* Format code with pre-commit
|
||||
* Replace case sensitivity check with setting (#273 thanks @patroqueeet)
|
||||
|
||||
|
||||
Version 0.9.8
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2008-2010 Marco Bonetti
|
||||
Copyright (c) 2008-2023 Marco Bonetti
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
|
|
|||
|
|
@ -16,7 +16,12 @@ Rosetta is a `Django <http://www.djangoproject.com/>`_ application that facilita
|
|||
|
||||
Because it doesn't export any models, Rosetta doesn't create any tables in your project's database. Rosetta can be installed and uninstalled by simply adding and removing a single entry in your project's `INSTALLED_APPS` and a single line in your main ``urls.py`` file.
|
||||
|
||||
Note: as of version 0.9.0, django-rosetta requires Django 1.11 or later, as of version 0.9.6, django-rosetta requires Django 2.2 or later, and as of version 0.9.9 django-rosetta supports Django 3.2 or later.
|
||||
Note:
|
||||
|
||||
* As of version 0.9.0, django-rosetta requires Django 1.11 or later
|
||||
* As of version 0.9.6, django-rosetta requires Django 2.2 or later
|
||||
* As of version 0.9.9 django-rosetta supports Django 3.2 or later
|
||||
* As of version 0.10.0, django-rosetta requires Django 4.2 or later
|
||||
|
||||
********
|
||||
Features
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ master_doc = "index"
|
|||
|
||||
# General information about the project.
|
||||
project = "Django Rosetta"
|
||||
copyright = "2008 – 2021 Marco Bonetti and contributors"
|
||||
copyright = "2008 – 2023 Marco Bonetti and contributors"
|
||||
author = "Marco Bonetti"
|
||||
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ release = get_version()
|
|||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
language = "en"
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Rosetta can be configured via the following parameters, to be defined in your pr
|
|||
* ``ROSETTA_LOGIN_URL``: Use this if you want to override the login URL for rosetta. Defaults to ``settings.LOGIN_URL``.
|
||||
* ``ROSETTA_LANGUAGES``: List of languages that Rosetta will offer to translate. This is useful when you wish to translate a language that is not yet defined in ``settings.LANGUAGES``. Defaults to ``settings.LANGUAGES``.
|
||||
* ``ROSETTA_SHOW_OCCURRENCES``: Determines whether occurrences (where the original text appears) should be shown next to the translations for context. Defaults to ``True``.
|
||||
* ``ROSETTA_CASE_SENSITIVE_FILESYSTEM``: Overrides auto-detection of case sensitive OS. Defaults to ``None`` which enables auto-detection. Useful when running case sensitive OS (e.g. Ubuntu) in docker on case insensitive OS (e.g. MacOS).
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,4 +38,4 @@ By default Rosetta hides its own catalog files in the file selection interface (
|
|||
Acknowledgments
|
||||
***************
|
||||
|
||||
* Rosetta uses the excellent `polib <https://bitbucket.org/izi/polib>`_ library to parse and handle gettext files.
|
||||
* Rosetta uses the excellent `polib <https://pypi.org/project/polib/>`_ library to parse and handle gettext files.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ order_by_type = true
|
|||
known_django = "django"
|
||||
known_django_third_party = "django_*"
|
||||
known_first_party = "apps,rosetta"
|
||||
sections = "FUTURE,STDLIB,THIRDPARTY,DJANGO,DJANGO_THIRD_PARTY,REST_FRAMEWORK,FIRSTPARTY,LOCALFOLDER"
|
||||
sections = "FUTURE,STDLIB,THIRDPARTY,DJANGO,DJANGO_THIRD_PARTY,FIRSTPARTY,LOCALFOLDER"
|
||||
skip_glob= "**/migrations/**"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,4 @@
|
|||
try:
|
||||
import django
|
||||
|
||||
if django.VERSION[:3] <= (3, 2, 0):
|
||||
default_app_config = "rosetta.apps.RosettaAppConfig"
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
VERSION = (0, 9, 9)
|
||||
VERSION = (0, 10, 0)
|
||||
|
||||
|
||||
def get_version(limit=3):
|
||||
|
|
|
|||
|
|
@ -71,11 +71,18 @@ def find_pos(lang, project_apps=True, django_apps=False, third_party_apps=False)
|
|||
)
|
||||
)
|
||||
|
||||
case_sensitive_file_system = True
|
||||
tmphandle, tmppath = tempfile.mkstemp()
|
||||
if os.path.exists(tmppath.upper()):
|
||||
# Case insensitive file system.
|
||||
case_sensitive_file_system = False
|
||||
# is OS case sensitive? settings preferred over auto detection
|
||||
case_sensitive_file_system = getattr(
|
||||
settings, "ROSETTA_CASE_SENSITIVE_FILESYSTEM", None
|
||||
)
|
||||
|
||||
# in case of no settings, attempt auto detection
|
||||
if case_sensitive_file_system is None:
|
||||
case_sensitive_file_system = True
|
||||
tmphandle, tmppath = tempfile.mkstemp()
|
||||
if os.path.exists(tmppath.upper()):
|
||||
# Case insensitive file system.
|
||||
case_sensitive_file_system = False
|
||||
|
||||
# django/locale
|
||||
if django_apps:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
{% include 'rosetta/css/rosetta.css' %}
|
||||
</style>
|
||||
{% block extra_styles %}{% endblock %}
|
||||
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
|
||||
<script src="{% static "admin/js/vendor/jquery/jquery.min.js" %}"></script>
|
||||
<script type="text/javascript">
|
||||
{% include 'rosetta/js/rosetta.js' %}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ $(document).ready(function() {
|
|||
if($(this).val()) {
|
||||
$('.alert', $(this).parents('tr')).remove();
|
||||
var RX = /%(?:\([^\s\)]*\))?[sdf]|\{[\w\d_]+?\}/g,
|
||||
origs=$(this).parents('tr').find('.original>.message').html().match(RX),
|
||||
origs=$(this).parents('tr').find('.original span').html().match(RX),
|
||||
trads=$(this).val().match(RX),
|
||||
error = $('<span class="alert">Unmatched variables</span>');
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import filecmp
|
|||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
from unittest import mock
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import vcr
|
||||
|
|
@ -17,6 +18,7 @@ from django.urls import resolve, reverse
|
|||
from django.utils.encoding import force_bytes
|
||||
|
||||
from rosetta import views
|
||||
from rosetta.poutil import find_pos
|
||||
from rosetta.signals import entry_changed, post_save
|
||||
from rosetta.storage import get_storage
|
||||
|
||||
|
|
@ -382,14 +384,16 @@ class RosettaTestCase(TestCase):
|
|||
|
||||
# Post a translation, it should have properly wrapped lines
|
||||
data = {
|
||||
"m_bb9d8fe6159187b9ea494c1b313d23d4": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean "
|
||||
"commodo ligula eget dolor. Aenean massa. Cum sociis natoque "
|
||||
"penatibus et magnis dis parturient montes, nascetur ridiculus "
|
||||
"mus. Donec quam felis, ultricies nec, pellentesque eu, pretium "
|
||||
"quis, sem. Nulla consequat massa quis enim. Donec pede justo, "
|
||||
"fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, "
|
||||
"rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum "
|
||||
"felis eu pede mollis pretium."
|
||||
"m_bb9d8fe6159187b9ea494c1b313d23d4": (
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean "
|
||||
"commodo ligula eget dolor. Aenean massa. Cum sociis natoque "
|
||||
"penatibus et magnis dis parturient montes, nascetur ridiculus "
|
||||
"mus. Donec quam felis, ultricies nec, pellentesque eu, pretium "
|
||||
"quis, sem. Nulla consequat massa quis enim. Donec pede justo, "
|
||||
"fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, "
|
||||
"rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum "
|
||||
"felis eu pede mollis pretium."
|
||||
)
|
||||
}
|
||||
r = self.client.post(self.xx_form_url, data)
|
||||
with open(self.dest_file, "r") as po_file:
|
||||
|
|
@ -762,8 +766,9 @@ class RosettaTestCase(TestCase):
|
|||
msg_hashes = message_hashes()
|
||||
data = {msg_hashes["String 1"]: "Translation 1"}
|
||||
self.client.post(self.xx_form_url, data)
|
||||
po_file_hash_before, mo_file_hash_before = file_hash(po_file), file_hash(
|
||||
mo_file
|
||||
po_file_hash_before, mo_file_hash_before = (
|
||||
file_hash(po_file),
|
||||
file_hash(mo_file),
|
||||
)
|
||||
|
||||
# Make a change to the translations
|
||||
|
|
@ -1053,6 +1058,23 @@ class RosettaTestCase(TestCase):
|
|||
resp = self.client.get(reverse("admin:index"))
|
||||
self.assertNotContains(resp, "rosetta-content-main")
|
||||
|
||||
@mock.patch("rosetta.poutil.os.path.exists")
|
||||
def test_273_override_case_sensitivity(self, path_mock):
|
||||
path_mock.exists.return_value = False
|
||||
# no setting
|
||||
find_pos("en")
|
||||
path_mock.assert_called_with(mock.ANY)
|
||||
|
||||
path_mock.reset_mock()
|
||||
with override_settings(ROSETTA_CASE_SENSITIVE_FILESYSTEM=False):
|
||||
find_pos("en")
|
||||
path_mock.isfile.assert_not_called()
|
||||
|
||||
path_mock.reset_mock()
|
||||
with override_settings(ROSETTA_CASE_SENSITIVE_FILESYSTEM=True):
|
||||
find_pos("en")
|
||||
path_mock.isfile.assert_not_called()
|
||||
|
||||
|
||||
# Stubbed access control function
|
||||
def no_access(user):
|
||||
|
|
|
|||
|
|
@ -48,8 +48,13 @@ def translate(text, from_language, to_language):
|
|||
|
||||
|
||||
def translate_by_deepl(text, to_language, auth_key):
|
||||
if auth_key.lower().endswith(":fx"):
|
||||
endpoint = "https://api-free.deepl.com"
|
||||
else:
|
||||
endpoint = "https://api.deepl.com"
|
||||
|
||||
r = requests.post(
|
||||
"https://api-free.deepl.com/v2/translate",
|
||||
f"{endpoint}/v2/translate",
|
||||
headers={"Authorization": f"DeepL-Auth-Key {auth_key}"},
|
||||
data={
|
||||
"target_lang": to_language.upper(),
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ urlpatterns = [
|
|||
name="rosetta-file-list",
|
||||
),
|
||||
re_path(
|
||||
r"^files/(?P<po_filter>[\w-]+)/(?P<lang_id>[\w\-_\.]+)/(?P<idx>\d+)/$",
|
||||
r"^files/(?P<po_filter>[\w-]+)/(?P<lang_id>[\w\-_\.@]+)/(?P<idx>\d+)/$",
|
||||
views.TranslationFormView.as_view(),
|
||||
name="rosetta-form",
|
||||
),
|
||||
re_path(
|
||||
r"^files/(?P<po_filter>[\w-]+)/(?P<lang_id>[\w\-_\.]+)/(?P<idx>\d+)/download/$",
|
||||
r"^files/(?P<po_filter>[\w-]+)/(?P<lang_id>[\w\-_\.@]+)/(?P<idx>\d+)/download/$",
|
||||
views.TranslationFileDownload.as_view(),
|
||||
name="rosetta-download-file",
|
||||
),
|
||||
|
|
|
|||
13
setup.py
13
setup.py
|
|
@ -52,19 +52,16 @@ setup(
|
|||
"Topic :: Software Development :: Localization",
|
||||
"Topic :: Software Development :: Internationalization",
|
||||
"Framework :: Django",
|
||||
"Framework :: Django :: 3.0",
|
||||
"Framework :: Django :: 3.1",
|
||||
"Framework :: Django :: 3.2",
|
||||
"Framework :: Django :: 4.0",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Framework :: Django :: 4.2",
|
||||
"Framework :: Django :: 5.0",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=["Django >= 2.2", "requests >= 2.1.0", "polib >= 1.1.0"],
|
||||
install_requires=["Django >= 4.2", "requests >= 2.30.0", "polib >= 1.1.0"],
|
||||
tests_require=["tox", "vcrpy"],
|
||||
cmdclass={"test": Tox},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ interactions:
|
|||
User-Agent:
|
||||
- python-requests/2.26.0
|
||||
method: POST
|
||||
uri: https://api-free.deepl.com/v2/translate
|
||||
uri: https://api.deepl.com/v2/translate
|
||||
response:
|
||||
body: {string: '{"translations": [{"detected_source_language": "EN", "text": "Salut tout le monde"}]}'}
|
||||
headers:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
import django
|
||||
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
|
|
@ -17,22 +15,13 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
if django.VERSION[:3] >= (3, 2, 0):
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
|
||||
"LOCATION": "127.0.0.1:11211",
|
||||
"KEY_PREFIX": "ROSETTA_TEST",
|
||||
}
|
||||
}
|
||||
else:
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"LOCATION": "127.0.0.1:11211",
|
||||
"KEY_PREFIX": "ROSETTA_TEST",
|
||||
}
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
|
||||
"LOCATION": "127.0.0.1:11211",
|
||||
"KEY_PREFIX": "ROSETTA_TEST",
|
||||
}
|
||||
}
|
||||
|
||||
# CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}}
|
||||
|
||||
|
|
@ -52,11 +41,9 @@ INSTALLED_APPS = [
|
|||
"django.contrib.sites",
|
||||
"django.contrib.messages",
|
||||
"rosetta",
|
||||
"rosetta.tests.test_app.apps.TestAppConfig",
|
||||
]
|
||||
|
||||
if django.VERSION[0:2] >= (1, 7):
|
||||
INSTALLED_APPS.append("rosetta.tests.test_app.apps.TestAppConfig")
|
||||
|
||||
LANGUAGE_CODE = "en"
|
||||
|
||||
MIDDLEWARE = (
|
||||
|
|
@ -84,8 +71,6 @@ SILENCED_SYSTEM_CHECKS = ["translation.E002"]
|
|||
|
||||
LOCALE_PATHS = [os.path.join(PROJECT_PATH, "locale")]
|
||||
|
||||
SOUTH_TESTS_MIGRATE = False
|
||||
|
||||
FIXTURE_DIRS = (os.path.join(PROJECT_PATH, "fixtures"),)
|
||||
STATIC_URL = "/static/"
|
||||
ROOT_URLCONF = "testproject.urls"
|
||||
|
|
@ -112,6 +97,8 @@ TEMPLATES = [
|
|||
}
|
||||
]
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
# SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
|
||||
|
|
|
|||
15
tox.ini
15
tox.ini
|
|
@ -1,16 +1,18 @@
|
|||
[tox]
|
||||
envlist =
|
||||
flake8,
|
||||
py{38,39,310}-django{32,40,41},
|
||||
py{38,39,310}-django42,
|
||||
py{310,311,312}-django50,
|
||||
gettext,
|
||||
docs
|
||||
|
||||
|
||||
[gh-actions]
|
||||
python =
|
||||
3.10: py310-django32, py310-django40, py310-django41
|
||||
3.9: py39-django32, py39-django40, py39-django41
|
||||
3.8: py38-django32, py38-django40, py38-django41
|
||||
3.12: py312-django50
|
||||
3.11: py311-django42, py311-django50
|
||||
3.10: py310-django42, py310-django50
|
||||
3.9: py39-django42
|
||||
|
||||
|
||||
skipsdist = True
|
||||
|
|
@ -27,9 +29,8 @@ setenv =
|
|||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
deps =
|
||||
django32: Django>=3.2,<=3.2.99
|
||||
django40: Django>=4.0,<4.1
|
||||
django41: Django>=4.1a,<4.2
|
||||
django42: Django>=4.2a,<4.3
|
||||
django50: Django>=5.0,<5.1
|
||||
|
||||
pymemcache
|
||||
requests
|
||||
|
|
|
|||
Loading…
Reference in a new issue