diff --git a/modoboa/core/__init__.py b/modoboa/core/__init__.py
index 7b9f6ba3f..641809b03 100644
--- a/modoboa/core/__init__.py
+++ b/modoboa/core/__init__.py
@@ -54,10 +54,9 @@ def load_core_settings():
This function must be manually called (see :file:`urls.py`) in
order to load base settings.
"""
- from modoboa.core.app_settings import GeneralParametersForm, UserSettings
+ from modoboa.core.app_settings import GeneralParametersForm
parameters.register(GeneralParametersForm, ugettext_lazy("General"))
- parameters.register(UserSettings, ugettext_lazy("General"))
events.declare(BASE_EVENTS)
diff --git a/modoboa/core/app_settings.py b/modoboa/core/app_settings.py
index e73a5fa53..648f02215 100644
--- a/modoboa/core/app_settings.py
+++ b/modoboa/core/app_settings.py
@@ -357,33 +357,3 @@ class GeneralParametersForm(parameters.AdminParametersForm):
})
else:
settings.AUTH_LDAP_GLOBAL_OPTIONS[ldap.OPT_REFERRALS] = False
-
-
-def translate_language_code(value):
- if "-" in value:
- return value.split("-")[0]
- return value
-
-
-class UserSettings(parameters.UserParametersForm):
- app = "core"
-
- sep = SeparatorField(label=ugettext_lazy("Display"))
-
- lang = forms.ChoiceField(
- initial=translate_language_code(settings.LANGUAGE_CODE),
- label=ugettext_lazy("Prefered language"),
- choices=[("cs", "čeština"),
- ("de", "deutsch"),
- ("en", "english"),
- ("es", "español"),
- ("fr", "français"),
- ("it", "italiano"),
- ("nl", "nederlands"),
- ("pt_PT", "português"),
- ("pt_BR", "português (BR)"),
- ("ru", "русский"),
- ("sv", "svenska")],
- help_text=ugettext_lazy("Prefered language to display pages"),
- widget=forms.Select(attrs={"class": "form-control"})
- )
diff --git a/modoboa/core/constants.py b/modoboa/core/constants.py
new file mode 100644
index 000000000..4a7f669ea
--- /dev/null
+++ b/modoboa/core/constants.py
@@ -0,0 +1,18 @@
+# coding: utf-8
+
+"""Core application constants."""
+
+
+LANGUAGES = (
+ ("cs", u"čeština"),
+ ("de", u"deutsch"),
+ ("en", u"english"),
+ ("es", u"español"),
+ ("fr", u"français"),
+ ("it", u"italiano"),
+ ("nl", u"nederlands"),
+ ("pt_PT", u"português"),
+ ("pt_BR", u"português (BR)"),
+ ("ru", u"русский"),
+ ("sv", u"svenska"),
+)
diff --git a/modoboa/core/forms.py b/modoboa/core/forms.py
index 2a35c7b6e..c1d96aa28 100644
--- a/modoboa/core/forms.py
+++ b/modoboa/core/forms.py
@@ -27,6 +27,9 @@ class LoginForm(forms.Form):
class ProfileForm(forms.ModelForm):
+
+ """Form to update User profile."""
+
oldpassword = forms.CharField(
label=ugettext_lazy("Old password"), required=False,
widget=forms.PasswordInput(attrs={"class": "form-control"})
@@ -42,7 +45,7 @@ class ProfileForm(forms.ModelForm):
class Meta:
model = User
- fields = ("first_name", "last_name")
+ fields = ("first_name", "last_name", "language")
widgets = {
'first_name': forms.TextInput(attrs={'class': 'form-control'}),
'last_name': forms.TextInput(attrs={'class': 'form-control'})
diff --git a/modoboa/core/migrations/0005_user_language.py b/modoboa/core/migrations/0005_user_language.py
new file mode 100644
index 000000000..3f61578ca
--- /dev/null
+++ b/modoboa/core/migrations/0005_user_language.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0004_auto_20150728_1228'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='user',
+ name='language',
+ field=models.CharField(default=b'en', help_text='Prefered language to display pages.', max_length=10, choices=[(b'cs', '\u010de\u0161tina'), (b'de', 'deutsch'), (b'en', 'english'), (b'es', 'espa\xf1ol'), (b'fr', 'fran\xe7ais'), (b'it', 'italiano'), (b'nl', 'nederlands'), (b'pt_PT', 'portugu\xeas'), (b'pt_BR', 'portugu\xeas (BR)'), (b'ru', '\u0440\u0443\u0441\u0441\u043a\u0438\u0439'), (b'sv', 'svenska')]),
+ preserve_default=True,
+ ),
+ ]
diff --git a/modoboa/core/models.py b/modoboa/core/models.py
index e407814b3..3b965bc3c 100644
--- a/modoboa/core/models.py
+++ b/modoboa/core/models.py
@@ -23,6 +23,8 @@ from modoboa.lib.exceptions import (
PermDeniedException, InternalError, BadRequest, Conflict
)
+from . import constants
+
try:
from modoboa.lib.ldap_utils import LDAPAuthBackend
@@ -60,6 +62,13 @@ class User(PermissionsMixin):
ugettext_lazy('last login'), default=timezone.now
)
+ language = models.CharField(
+ max_length=10, default="en", choices=constants.LANGUAGES,
+ help_text=ugettext_lazy(
+ "Prefered language to display pages."
+ )
+ )
+
objects = UserManager()
USERNAME_FIELD = 'username'
diff --git a/modoboa/core/templates/core/user_preferences.html b/modoboa/core/templates/core/user_preferences.html
index ef073e653..8bd449e74 100644
--- a/modoboa/core/templates/core/user_preferences.html
+++ b/modoboa/core/templates/core/user_preferences.html
@@ -1,9 +1,16 @@
{% load i18n %}{% load url from future %}
{% trans "Preferences" %} {% trans "Customize Modoboa" %}
-
+{% if forms %}
+
+{% else %}
+
+ {% trans "No preferences available." %}
+
+{% endif %}
diff --git a/modoboa/core/tests.py b/modoboa/core/tests.py
index 3a8e0aa42..aaeca7d03 100644
--- a/modoboa/core/tests.py
+++ b/modoboa/core/tests.py
@@ -22,7 +22,7 @@ class ProfileTestCase(ModoTestCase):
* A normal user changes his password
"""
self.ajax_post(reverse("core:user_profile"),
- {"oldpassword": "password",
+ {"language": "en", "oldpassword": "password",
"newpassword": "12345Toi", "confirmation": "12345Toi"})
self.clt.logout()
@@ -42,7 +42,7 @@ class ProfileTestCase(ModoTestCase):
self.ajax_post(
reverse("core:user_profile"),
- {"oldpassword": "toto",
+ {"language": "en", "oldpassword": "toto",
"newpassword": "Toto1234", "confirmation": "Toto1234"}
)
self.clt.logout()
diff --git a/modoboa/core/views/auth.py b/modoboa/core/views/auth.py
index 44325a366..2fe6a4062 100644
--- a/modoboa/core/views/auth.py
+++ b/modoboa/core/views/auth.py
@@ -4,11 +4,12 @@ import logging
from django.contrib.auth import authenticate, login, logout
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
+from django.utils import translation
from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache
from modoboa.core.forms import LoginForm
-from modoboa.lib import events, parameters
+from modoboa.lib import events
from modoboa.lib.web_utils import _render_to_string
@@ -26,8 +27,9 @@ def dologin(request):
if not form.cleaned_data["rememberme"]:
request.session.set_expiry(0)
- request.session["django_language"] = \
- parameters.get_user(request.user, "LANG")
+ translation.activate(request.user.language)
+ request.session[translation.LANGUAGE_SESSION_KEY] = (
+ request.user.language)
logger.info(
_("User '%s' successfully logged in" % user.username)
diff --git a/modoboa/core/views/user.py b/modoboa/core/views/user.py
index 7c444bbd6..91583856b 100644
--- a/modoboa/core/views/user.py
+++ b/modoboa/core/views/user.py
@@ -1,15 +1,17 @@
"""Simple user views."""
-from django.contrib.auth.decorators import login_required
from django.shortcuts import render
+from django.utils import translation
from django.utils.translation import ugettext as _
-from modoboa.core.forms import ProfileForm
+from django.contrib.auth.decorators import login_required
+
from modoboa.lib import events, parameters
from modoboa.lib.cryptutils import encrypt
from modoboa.lib.web_utils import (
_render_to_string, render_to_json_response
)
+from ..forms import ProfileForm
@login_required
@@ -23,6 +25,7 @@ def index(request, tplname="core/user_index.html"):
@login_required
def profile(request, tplname='core/user_profile.html'):
+ """Profile detail/update view."""
update_password = True
if True in events.raiseQueryEvent("PasswordChange", request.user):
update_password = False
@@ -36,8 +39,12 @@ def profile(request, tplname='core/user_profile.html'):
if update_password and form.cleaned_data["confirmation"] != "":
request.session["password"] = encrypt(
form.cleaned_data["confirmation"])
+ translation.activate(request.user.language)
+ request.session[translation.LANGUAGE_SESSION_KEY] = (
+ request.user.language)
return render_to_json_response(_("Profile updated"))
- return render_to_json_response({'form_errors': form.errors}, status=400)
+ return render_to_json_response(
+ {'form_errors': form.errors}, status=400)
form = ProfileForm(update_password, instance=request.user)
return render_to_json_response({
@@ -50,7 +57,7 @@ def profile(request, tplname='core/user_profile.html'):
@login_required
def preferences(request):
if request.method == "POST":
- for formdef in parameters.get_user_forms(request.user, request.POST)():
+ for formdef in parameters.get_user_forms(request.user, request.POST):
form = formdef["form"]
if form.is_valid():
form.save()
diff --git a/modoboa/lib/migrations/0004_auto_20151114_1409.py b/modoboa/lib/migrations/0004_auto_20151114_1409.py
new file mode 100644
index 000000000..e66d38167
--- /dev/null
+++ b/modoboa/lib/migrations/0004_auto_20151114_1409.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+def move_language_preference(apps, schema_editor):
+ """Move language from parameters to User model."""
+ UserParameter = apps.get_model("lib", "UserParameter")
+ for uparam in UserParameter.objects.filter(name="core.LANG"):
+ uparam.user.language = uparam.value
+ uparam.user.save()
+ uparam.delete()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lib', '0003_rename_parameters'),
+ ('core', '0005_user_language'),
+ ]
+
+ operations = [
+ migrations.RunPython(move_language_preference),
+ ]
diff --git a/modoboa/lib/parameters.py b/modoboa/lib/parameters.py
index a18463030..1ea5eadc2 100644
--- a/modoboa/lib/parameters.py
+++ b/modoboa/lib/parameters.py
@@ -332,18 +332,18 @@ def get_admin_forms(*args, **kwargs):
def get_user_forms(user, *args, **kwargs):
+ """Return an instance of each user-level forms."""
kwargs["user"] = user
sorted_apps = get_sorted_apps('U', first="general")
-
- def realfunc():
- for app in sorted_apps:
- formdef = _params['U'][app]
- if not formdef["form"].has_access(user):
- continue
- yield {"label": formdef["label"],
- "form": formdef["form"](*args, **kwargs)}
-
- return realfunc
+ result = []
+ for app in sorted_apps:
+ formdef = _params["U"][app]
+ if not formdef["form"].has_access(user):
+ continue
+ result.append({
+ "label": formdef["label"],
+ "form": formdef["form"](*args, **kwargs)})
+ return result
def get_parameter_form(level, name, app=None):