Fixed tabs don't properly support two-part language codes. Resolves issue 63.

This commit is contained in:
Dirk Eschler 2012-10-19 13:32:33 +02:00
parent 429788382b
commit 9d58478b2e
4 changed files with 75 additions and 31 deletions

View file

@ -1,3 +1,9 @@
CHANGED: Modeltranslation related css class prefix to 'mt'.
FIXED: Tabs don't properly support two-part language codes.
(resolves issue 63)
v0.4.0-beta2
============
Date: 2012-10-17

View file

@ -9,7 +9,8 @@ from django.utils import translation
from modeltranslation.settings import DEFAULT_LANGUAGE
from modeltranslation.translator import translator
from modeltranslation.utils import (get_translation_fields,
build_localized_fieldname)
build_localized_fieldname,
build_css_class)
class TranslationBaseModelAdmin(BaseModelAdmin):
@ -56,12 +57,15 @@ class TranslationBaseModelAdmin(BaseModelAdmin):
self.model._meta.get_field(orig_fieldname), **kwargs)
field.widget = deepcopy(orig_formfield.widget)
css_classes = field.widget.attrs.get('class', '').split(' ')
css_classes.append('modeltranslation')
css_classes.append('mt')
# Add localized fieldname css class
css_classes.append(
build_css_class(db_field.name, 'mt-field'))
if db_field.language == DEFAULT_LANGUAGE:
# Add another css class to identify a default modeltranslation
# widget.
css_classes.append('modeltranslation-default')
css_classes.append('mt-default')
if (orig_formfield.required or
self._orig_was_required.get(
'%s.%s' % (db_field.model._meta, orig_fieldname))):

View file

@ -16,44 +16,35 @@ var google, django, gettext;
/** Returns a grouped set of all text based model translation fields.
* The returned datastructure will look something like this:
* {
* 'title': {
* 'en': HTMLInputElement,
* 'de': HTMLInputElement,
* 'fr': HTMLInputElement
* },
* 'body': {
* 'en': HTMLTextAreaElement,
* 'de': HTMLTextAreaElement,
* 'fr': HTMLTextAreaElement
* }
* 'title': {
* 'en': HTMLInputElement,
* 'de': HTMLInputElement,
* 'zh_tw': HTMLInputElement
* },
* 'body': {
* 'en': HTMLTextAreaElement,
* 'de': HTMLTextAreaElement,
* 'zh_tw': HTMLTextAreaElement
* }
* }
*/
var translation_fields = $('.modeltranslation').filter(
var translation_fields = $('.mt').filter(
'input[type=text]:visible, textarea:visible').filter(
':parents(.tabular)'), // exclude tabular inlines
grouped_translations = {};
translation_fields.each(function (i, el) {
/*
// FIXME: Fails if there's an inline which has the same field name as
// the edited object.
// Extract fieldname and original language code from class attribute
var css_lang_suffix = 'modeltranslation-field-';
var name = '';
var lang = '';
var field_suffix = 'mt-field-',
name = '',
lang = '';
$.each($(el).attr('class').split(' '), function(j, cls) {
if (cls.substring(0, css_lang_suffix.length) === css_lang_suffix) {
var v = cls.substring(css_lang_suffix.length,
cls.length).split('__');
if (cls.substring(0, field_suffix.length) === field_suffix) {
var v = cls.substring(field_suffix.length,
cls.length).split('-');
name = v[0];
lang = v[1];
}
});
*/
var name = $(el).attr('name').split('_'),
lang = name.pop();
name = name.join('_');
if (!grouped_translations[name]) {
grouped_translations[name] = {};
}
@ -89,7 +80,7 @@ var google, django, gettext;
}
container.find('script').remove();
panel = $('<div id="' + id + '"></div>').append(container);
tab = $('<li' + (label.hasClass('required') ? ' class="required"' : '') + '><a href="#' + id + '">' + lang + '</a></li>');
tab = $('<li' + (label.hasClass('required') ? ' class="required"' : '') + '><a href="#' + id + '">' + lang.replace('_', '-') + '</a></li>');
tabs_list.append(tab);
tabs_container.append(panel);
});
@ -112,7 +103,7 @@ var google, django, gettext;
});
});
$.each(unique_languages, function (i, language) {
select.append($('<option value="' + i + '">' + language + '</option>'));
select.append($('<option value="' + i + '">' + language.replace('_', '-') + '</option>'));
});
select.change(function (e) {
$.each(tabs, function (i, tab) {

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from django.conf import global_settings
from django.utils.encoding import force_unicode
from django.utils.translation import get_language as _get_language
from django.utils.functional import lazy
@ -33,3 +34,45 @@ def build_localized_fieldname(field_name, lang):
def _build_localized_verbose_name(verbose_name, lang):
return u'%s [%s]' % (force_unicode(verbose_name), lang)
build_localized_verbose_name = lazy(_build_localized_verbose_name, unicode)
def _join_css_class(bits, offset):
if ('-'.join(bits[-offset:]) in
[l[0] for l in global_settings.LANGUAGES]):
return '%s-%s' % ('_'.join(bits[:len(bits) - offset]),
'_'.join(bits[-offset:]))
return ''
def build_css_class(localized_fieldname, prefix=''):
"""
Returns a css class based on ``localized_fieldname`` which is easily
splitable and capable of regionalized language codes.
Takes an optional ``prefix`` which is prepended to the returned string.
"""
bits = localized_fieldname.split('_')
css_class = ''
if bits[0] == '':
return ''
if len(bits) == 1:
css_class = str(localized_fieldname)
elif len(bits) == 2:
# Fieldname without underscore and short language code
# Examples:
# 'foo_de' --> 'foo-de',
# 'bar_en' --> 'bar-en'
css_class = '-'.join(bits)
elif len(bits) > 2:
# Try regionalized language code
# Examples:
# 'foo_es_ar' --> 'foo-es_ar',
# 'foo_bar_zh_tw' --> 'foo_bar-zh_tw'
css_class = _join_css_class(bits, 2)
if not css_class:
# Try short language code
# Examples:
# 'foo_bar_de' --> 'foo_bar-de',
# 'foo_bar_baz_de' --> 'foo_bar_baz-de'
css_class = _join_css_class(bits, 1)
return '%s-%s' % (prefix, css_class) if prefix else css_class