Fix section counting/targetting from search snippet
[wolnelektury.git] / apps / modeltranslation / utils.py
1 # -*- coding: utf-8 -*-
2 from django.db import models
3 from django.conf import settings
4 from django.core.exceptions import ValidationError
5 from django.contrib.contenttypes.models import ContentType
6 from django.utils.translation import get_language as _get_language
7
8
9 def get_language():
10     """
11     Return an active language code that is guaranteed to be in
12     settings.LANGUAGES (Django does not seem to guarantee this for us.)
13
14     """
15     lang = _get_language()
16     available_languages = [l[0] for l in settings.LANGUAGES]
17     if lang not in available_languages and '-' in lang:
18         lang = lang.split('-')[0]
19     if lang in available_languages:
20         return lang
21     return available_languages[0]
22
23
24 def get_translation_fields(field):
25     """Returns a list of localized fieldnames for a given field."""
26     return [build_localized_fieldname(field, l[0]) for l in settings.LANGUAGES]
27
28
29 def build_localized_fieldname(field_name, lang):
30     return '%s_%s' % (field_name, lang.replace('-', '_'))
31
32
33 class TranslationFieldDescriptor(object):
34     """A descriptor used for the original translated field."""
35     def __init__(self, name, initial_val=""):
36         """
37         The ``name`` is the name of the field (which is not available in the
38         descriptor by default - this is Python behaviour).
39         """
40         self.name = name
41         self.val = initial_val
42
43     def __set__(self, instance, value):
44         lang = get_language()
45         loc_field_name = build_localized_fieldname(self.name, lang)
46         # also update the translation field of the current language
47         setattr(instance, loc_field_name, value)
48         # update the original field via the __dict__ to prevent calling the
49         # descriptor
50         instance.__dict__[self.name] = value
51
52     def __get__(self, instance, owner):
53         if not instance:
54             raise ValueError(u"Translation field '%s' can only be "
55                               "accessed via an instance not via "
56                               "a class." % self.name)
57         lang = get_language()
58         loc_field_name = build_localized_fieldname(self.name, lang)
59         if hasattr(instance, loc_field_name):
60             return getattr(instance, loc_field_name) or \
61                    instance.__dict__[self.name]
62         return instance.__dict__[self.name]
63
64
65 #def create_model(name, fields=None, app_label='', module='', options=None,
66                  #admin_opts=None):
67     #"""
68     #Create specified model.
69     #This is taken from http://code.djangoproject.com/wiki/DynamicModels
70     #"""
71     #class Meta:
72         ## Using type('Meta', ...) gives a dictproxy error during model
73         ## creation
74         #pass
75
76     #if app_label:
77         ## app_label must be set using the Meta inner class
78         #setattr(Meta, 'app_label', app_label)
79
80     ## Update Meta with any options that were provided
81     #if options is not None:
82         #for key, value in options.iteritems():
83             #setattr(Meta, key, value)
84
85     ## Set up a dictionary to simulate declarations within a class
86     #attrs = {'__module__': module, 'Meta': Meta}
87
88     ## Add in any fields that were provided
89     #if fields:
90         #attrs.update(fields)
91
92     ## Create the class, which automatically triggers ModelBase processing
93     #model = type(name, (models.Model,), attrs)
94
95     ## Create an Admin class if admin options were provided
96     #if admin_opts is not None:
97         #class Admin(admin.ModelAdmin):
98             #pass
99         #for key, value in admin_opts:
100             #setattr(Admin, key, value)
101         #admin.site.register(model, Admin)
102
103     #return model
104
105
106 def copy_field(field):
107     """
108     Instantiate a new field, with all of the values from the old one, except
109     the to and to_field in the case of related fields.
110
111     This taken from http://www.djangosnippets.org/snippets/442/
112     """
113     base_kw = dict([(n, getattr(field, n, '_null')) for n in \
114               models.fields.Field.__init__.im_func.func_code.co_varnames])
115     if isinstance(field, models.fields.related.RelatedField):
116         rel = base_kw.get('rel')
117         rel_kw = dict([(n, getattr(rel, n, '_null')) for n in \
118                  rel.__init__.im_func.func_code.co_varnames])
119         if isinstance(field, models.fields.related.ForeignKey):
120             base_kw['to_field'] = rel_kw.pop('field_name')
121         base_kw.update(rel_kw)
122     base_kw.pop('self')
123     return field.__class__(**base_kw)