diff --git a/plinth/__main__.py b/plinth/__main__.py index 1fe4ef30d..8453bba56 100644 --- a/plinth/__main__.py +++ b/plinth/__main__.py @@ -213,6 +213,17 @@ def configure_django(): if cfg.secure_proxy_ssl_header: secure_proxy_ssl_header = (cfg.secure_proxy_ssl_header, 'https') + # Read translated languages from the 'locale' directory + languages = [('en', 'English')] + locale_dir = os.path.join(os.path.dirname(__file__), 'locale') + if os.path.isdir(locale_dir): + translated_language_codes = next(os.walk(locale_dir))[1] + all_languages = dict(django.conf.global_settings.LANGUAGES) + for code in translated_language_codes: + if code in all_languages: + languages.append((code, all_languages[code])) + languages = sorted(languages, key=lambda tup: tup[1]) + django.conf.settings.configure( ALLOWED_HOSTS=['*'], CACHES={'default': @@ -222,6 +233,7 @@ def configure_django(): 'NAME': cfg.store_file}}, DEBUG=cfg.debug, INSTALLED_APPS=applications, + LANGUAGES=languages, LOGGING=logging_configuration, LOGIN_URL='users:login', LOGIN_REDIRECT_URL='apps:index', diff --git a/plinth/modules/config/config.py b/plinth/modules/config/config.py index 9989c406c..6b7aaefcf 100644 --- a/plinth/modules/config/config.py +++ b/plinth/modules/config/config.py @@ -23,7 +23,9 @@ from django import forms from django.contrib import messages from django.core import validators from django.core.exceptions import ValidationError +from django.conf import settings from django.template.response import TemplateResponse +from django.utils import translation from django.utils.translation import ugettext as _, ugettext_lazy import logging import re @@ -51,6 +53,16 @@ def get_domainname(): return '.'.join(fqdn.split('.')[1:]) +def get_language(request): + """Return the current language setting""" + # TODO: Store the language per user in kvstore, + # taking care of setting language on login, and adapting kvstore when + # renaming/deleting users + + # The session contains more accurate information than request.LANGUAGE_CODE + return request.session[translation.LANGUAGE_SESSION_KEY] + + class TrimmedCharField(forms.CharField): """Trim the contents of a CharField""" def clean(self, value): @@ -104,6 +116,14 @@ class ConfigurationForm(forms.Form): ugettext_lazy('Invalid domain name')), domain_label_validator]) + language = forms.ChoiceField( + label=ugettext_lazy('Language'), + help_text=\ + ugettext_lazy('Language for this freedombox web administration ' + 'interface'), + required=False, + choices=settings.LANGUAGES) + def init(): """Initialize the module""" @@ -114,7 +134,7 @@ def init(): def index(request): """Serve the configuration form""" - status = get_status() + status = get_status(request) form = None @@ -124,7 +144,7 @@ def index(request): # pylint: disable-msg=E1101 if form.is_valid(): _apply_changes(request, status, form.cleaned_data) - status = get_status() + status = get_status(request) form = ConfigurationForm(initial=status, prefix='configuration') else: @@ -135,10 +155,11 @@ def index(request): 'form': form}) -def get_status(): +def get_status(request): """Return the current status""" return {'hostname': get_hostname(), - 'domainname': get_domainname()} + 'domainname': get_domainname(), + 'language': get_language(request)} def _apply_changes(request, old_status, new_status): @@ -151,8 +172,6 @@ def _apply_changes(request, old_status, new_status): .format(exception=exception)) else: messages.success(request, _('Hostname set')) - else: - messages.info(request, _('Hostname is unchanged')) if old_status['domainname'] != new_status['domainname']: try: @@ -162,8 +181,17 @@ def _apply_changes(request, old_status, new_status): .format(exception=exception)) else: messages.success(request, _('Domain name set')) - else: - messages.info(request, _('Domain name is unchanged')) + + if old_status['language'] != new_status['language']: + language = new_status['language'] + try: + translation.activate(language) + request.session[translation.LANGUAGE_SESSION_KEY] = language + except Exception as exception: + messages.error(request, _('Error setting language: {exception}') + .format(exception=exception)) + else: + messages.success(request, _('Language changed')) def set_hostname(hostname): diff --git a/plinth/modules/config/tests/test_config.py b/plinth/modules/config/tests/test_config.py index 3822e942b..87bb95dbd 100644 --- a/plinth/modules/config/tests/test_config.py +++ b/plinth/modules/config/tests/test_config.py @@ -19,8 +19,11 @@ Tests for config module. """ +import os import unittest +from plinth import __main__ as plinth_main + from ..config import ConfigurationForm @@ -65,3 +68,12 @@ class TestConfig(unittest.TestCase): form = ConfigurationForm({'hostname': 'example', 'domainname': domainname}) self.assertFalse(form.is_valid()) + + def test_locale_path(self): + """ + Test that the 'locale' directory is in the same folder as __main__.py. + This is required for detecting translated languages. + """ + plinth_dir = os.path.dirname(plinth_main.__file__) + locale_dir = os.path.join(plinth_dir, 'locale') + self.assertTrue(os.path.isdir(locale_dir))