diff --git a/CHANGES b/CHANGES
index d7d8af8..8557ae8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,13 @@
Version History
===============
+
+Version 0.9.3 (unreleased)
+--------------------------
+* Added a tooltip to explain fuzzy entries (#206)
+* New ROSETTA_LANGUAGES setting allows for translating languages which are not yet in LANGUAGES (#219)
+
+
Version 0.9.2
-------------
* Cleanup of imports, and use relative imports. Hopefully fixes #209.
diff --git a/docs/settings.rst b/docs/settings.rst
index bdef1a2..fa17235 100644
--- a/docs/settings.rst
+++ b/docs/settings.rst
@@ -22,6 +22,7 @@ Rosetta can be configured via the following parameters, to be defined in your pr
* ``ROSETTA_ENABLE_REFLANG``: Enables a selector for picking a reference language other than English. Defaults to ``False``.
* ``ROSETTA_SHOW_AT_ADMIN_PANEL``: Adds a handy link to Rosetta at the bottom of the Django admin apps index. Defaults to ``False``.
* ``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``.
Storages
--------
diff --git a/rosetta/__init__.py b/rosetta/__init__.py
index b9a2cb4..8726f2a 100644
--- a/rosetta/__init__.py
+++ b/rosetta/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (0, 9, 2)
+VERSION = (0, 9, 3)
default_app_config = "rosetta.apps.RosettaAppConfig"
diff --git a/rosetta/conf/__init__.py b/rosetta/conf/__init__.py
index eb31ac5..483def0 100644
--- a/rosetta/conf/__init__.py
+++ b/rosetta/conf/__init__.py
@@ -51,6 +51,8 @@ class RosettaSettings(object):
'ROSETTA_AUTO_COMPILE': ('AUTO_COMPILE', True),
'ROSETTA_SHOW_AT_ADMIN_PANEL': ('SHOW_AT_ADMIN_PANEL', False),
'ROSETTA_LOGIN_URL': ('LOGIN_URL', dj_settings.LOGIN_URL),
+
+ 'ROSETTA_LANGUAGES': ('ROSETTA_LANGUAGES', dj_settings.LANGUAGES)
}
def __init__(self):
diff --git a/rosetta/templates/rosetta/css/rosetta.css b/rosetta/templates/rosetta/css/rosetta.css
index 9472812..0cc6aba 100644
--- a/rosetta/templates/rosetta/css/rosetta.css
+++ b/rosetta/templates/rosetta/css/rosetta.css
@@ -35,3 +35,14 @@ div.module {margin-bottom: 20px;}
#toolbar #translate-all { float:right}
#toolbar form { float:left; }
#changelist table thead th { padding: 2px 5px; }
+
+
+.info-tip::after {
+ content: '?';
+ color: white;
+ background-color: #bbb;
+ margin-left: 5px;
+ padding: 1px 5px;
+ border-radius: 10px;
+ font-size: 11px;
+}
diff --git a/rosetta/templates/rosetta/file-list.html b/rosetta/templates/rosetta/file-list.html
index 82f6bef..5d91d65 100644
--- a/rosetta/templates/rosetta/file-list.html
+++ b/rosetta/templates/rosetta/file-list.html
@@ -1,5 +1,5 @@
{% extends "rosetta/base.html" %}
-{% load i18n %}
+{% load i18n static %}
{% block pagetitle %}{{block.super}} - {% trans "Language selection" %}{% endblock %}
@@ -32,7 +32,7 @@
diff --git a/rosetta/tests/tests.py b/rosetta/tests/tests.py
index 78cc1ae..2888802 100644
--- a/rosetta/tests/tests.py
+++ b/rosetta/tests/tests.py
@@ -87,7 +87,7 @@ class RosettaTestCase(TestCase):
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content)
)
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_2_PickFile(self):
@@ -101,7 +101,7 @@ class RosettaTestCase(TestCase):
self.assertTrue('content-type' in r._headers.keys())
self.assertTrue('application/x-zip' in r._headers.get('content-type'))
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_4_DoChanges(self):
@@ -137,7 +137,7 @@ class RosettaTestCase(TestCase):
self.assertTrue('String 2' in str(r.content))
self.assertTrue('Hello, world' in str(r.content))
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_5_TestIssue67(self):
@@ -171,7 +171,7 @@ class RosettaTestCase(TestCase):
self.assertTrue('or n%100>=20) ? 1 : 2)' not in str(content))
del(content)
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_6_ExcludedApps(self):
@@ -190,7 +190,7 @@ class RosettaTestCase(TestCase):
r = self.client.get(self.project_file_list_url)
self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po')
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_8_hideObsoletes(self):
@@ -297,7 +297,7 @@ class RosettaTestCase(TestCase):
self.assertTrue(r.content)
self.assertEqual(r.status_code, 200)
- @override_settings(LANGUAGES=(('fr', 'French'), ('xx', 'Dummy Language'),))
+ @override_settings(ROSETTA_LANGUAGES=(('fr', 'French'), ('xx', 'Dummy Language'),))
def test_13_catalog_filters(self):
r = self.client.get(self.third_party_file_list_url)
self.assertTrue(
@@ -488,7 +488,7 @@ class RosettaTestCase(TestCase):
self.assertTrue('m_4765f7de94996d3de5975fa797c3451f' in str(r.content))
self.assertTrue('m_08e4e11e2243d764fc45a5a4fba5d0f2' in str(r.content))
- @override_settings(LANGUAGES=(
+ @override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
def test_23_save_header_data(self):
@@ -590,7 +590,7 @@ class RosettaTestCase(TestCase):
@override_settings(
ROSETTA_POFILENAMES=('pr44.po', ),
- LANGUAGES=(('xx', 'dummy language'),)
+ ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
)
def test_30_pofile_names(self):
os.unlink(self.dest_file)
@@ -648,7 +648,7 @@ class RosettaTestCase(TestCase):
@override_settings(
ROSETTA_ENABLE_REFLANG=True,
- LANGUAGES=(('xx', 'dummy language'),)
+ ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
)
def test_33_reflang(self):
self.copy_po_file_from_template('./django.po.issue60.template')
@@ -705,7 +705,7 @@ class RosettaTestCase(TestCase):
r = self.client.get(self.all_file_list_url)
self.assertContains(r, 'locale/bs-Cyrl-BA/LC_MESSAGES/django.po')
- @override_settings(LANGUAGES=(('yy-Anot', u'Yet Another dummy language'),))
+ @override_settings(ROSETTA_LANGUAGES=(('yy-Anot', u'Yet Another dummy language'),))
def test_37_issue_133_complex_locales(self):
r = self.client.get(self.all_file_list_url)
self.assertContains(r, 'locale/yy_Anot/LC_MESSAGES/django.po')
@@ -864,7 +864,7 @@ class RosettaTestCase(TestCase):
self.assertEqual(view.po_file_path, self.dest_file)
# But if the language isn't an option, we get a 404
- with self.settings(LANGUAGES=[l for l in settings.LANGUAGES if l[0] != 'xx']):
+ with self.settings(ROSETTA_LANGUAGES=[l for l in settings.LANGUAGES if l[0] != 'xx']):
view = self._setup_view(
view=views.TranslationFormView(),
request=request,
@@ -983,6 +983,20 @@ class RosettaTestCase(TestCase):
self.assertRedirects(r, '/custom-url/?next=/rosetta/files/all/', fetch_redirect_response=False)
self.assertEqual(302, r.status_code)
+ def test_51_rosetta_languages(self):
+ self.assertTrue('xx' in dict(settings.LANGUAGES))
+ self.assertFalse('yy' in dict(settings.LANGUAGES))
+
+ with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), )):
+ r = self.client.get(self.project_file_list_url)
+ self.assertTrue('foo language' in str(r.content))
+ self.assertFalse('bar language' in str(r.content))
+
+ with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), ('yy', 'bar language'), )):
+ r = self.client.get(self.project_file_list_url)
+ self.assertTrue('foo language' in str(r.content))
+ self.assertTrue('bar language' in str(r.content))
+
# Stubbed access control function
def no_access(user):
diff --git a/rosetta/views.py b/rosetta/views.py
index 2c30bfa..3db3112 100644
--- a/rosetta/views.py
+++ b/rosetta/views.py
@@ -102,14 +102,14 @@ class RosettaFileLevelMixin(RosettaBaseMixin):
def language_id(self):
"""Determine/return the language id from the url kwargs, after
validating that:
- 1. the language is in settings.LANGUAGES, and
+ 1. the language is in rosetta_settings.ROSETTA_LANGUAGES, and
2. the current user is permitted to translate that language
(If either of the above fail, throw a 404.)
"""
# (Formerly known as "rosetta_i18n_lang_code")
lang_id = self.kwargs['lang_id']
- if lang_id not in {l[0] for l in settings.LANGUAGES}:
+ if lang_id not in {l[0] for l in rosetta_settings.ROSETTA_LANGUAGES}:
raise Http404
if not can_translate_language(self.request.user, lang_id):
raise Http404
@@ -218,7 +218,7 @@ class TranslationFileListView(RosettaBaseMixin, TemplateView):
languages = []
has_pos = False
- for language in settings.LANGUAGES:
+ for language in rosetta_settings.ROSETTA_LANGUAGES:
if not can_translate_language(self.request.user, language[0]):
continue
@@ -445,7 +445,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
# Handle REF_LANG setting; mark up our entries with the reg lang's
# corresponding translations
- LANGUAGES = list(settings.LANGUAGES)
+ LANGUAGES = list(rosetta_settings.ROSETTA_LANGUAGES)
if rosetta_settings.ENABLE_REFLANG:
if self.ref_lang_po_file:
for o in paginator.object_list:
@@ -485,7 +485,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
main_language = None
if main_language_id and main_language_id != self.language_id:
# Translate from id to language name
- for language in settings.LANGUAGES:
+ for language in rosetta_settings.ROSETTA_LANGUAGES:
if language[0] == main_language_id:
main_language = _(language[1])
break
@@ -502,7 +502,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
# Collect some constants for the template
rosetta_i18n_lang_name = six.text_type(
- dict(settings.LANGUAGES).get(self.language_id)
+ dict(rosetta_settings.ROSETTA_LANGUAGES).get(self.language_id)
)
# "bidi" as in "bi-directional"
rosetta_i18n_lang_bidi = self.language_id.split('-')[0] in settings.LANGUAGES_BIDI
@@ -552,11 +552,11 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
"""Return the language id for the "reference language" (the language to
be translated *from*, if not English).
- Throw a 404 if it's not in settings.LANGUAGES.
+ Throw a 404 if it's not in rosetta_settings.ROSETTA_LANGUAGES.
"""
ref_lang = self._request_request('ref_lang', 'msgid')
if ref_lang != 'msgid':
- allowed_languages = {l[0] for l in settings.LANGUAGES}
+ allowed_languages = {l[0] for l in rosetta_settings.ROSETTA_LANGUAGES}
if ref_lang not in allowed_languages:
raise Http404
return ref_lang
diff --git a/testproject/locale/yy/LC_MESSAGES/django.po b/testproject/locale/yy/LC_MESSAGES/django.po
new file mode 100644
index 0000000..8938f73
--- /dev/null
+++ b/testproject/locale/yy/LC_MESSAGES/django.po
@@ -0,0 +1,35 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-04-07 04:49-0500\n"
+"PO-Revision-Date: 2019-04-07 05:09-0551\n"
+"Last-Translator: b' '\n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+"X-Translated-Using: django-rosetta 0.9.3\n"
+
+#: templates/test.html:3
+msgid "Some text to translate"
+msgstr "asdasd"
+
+#: templates/test.html:5
+#, python-format
+msgid ""
+"\n"
+"one bottle of beer on the wall\n"
+msgid_plural ""
+"\n"
+"%(num_bottles)s bottles of beer on the wall\n"
+msgstr[0] ""
+msgstr[1] ""