Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
14 KiB
322 lines
14 KiB
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
* Copyright (C) 2010, mbonetti <http://code.google.com/u/mbonetti/>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
"""
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth.decorators import user_passes_test
|
|
from django.core.paginator import Paginator, InvalidPage
|
|
from django.core.urlresolvers import reverse, resolve, Resolver404
|
|
from django.http import Http404, HttpResponseRedirect, HttpResponse
|
|
from django.shortcuts import render_to_response
|
|
from django.utils.encoding import smart_unicode, force_unicode, iri_to_uri
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.decorators.cache import never_cache
|
|
from rosetta.polib import pofile
|
|
from rosetta.poutil import find_pos, pagination_range
|
|
from rosetta.conf import settings as rosetta_settings
|
|
import re, os, rosetta, datetime, unicodedata
|
|
from django.template import RequestContext
|
|
|
|
|
|
try:
|
|
resolve(settings.LOGIN_URL)
|
|
except Resolver404:
|
|
try:
|
|
resolve('/admin/')
|
|
except Resolver404:
|
|
raise Exception('Rosetta cannot log you in!\nYou must define a LOGIN_URL in your settings if you don\'t run the Django admin site at a standard URL.')
|
|
else:
|
|
LOGIN_URL = '/admin/'
|
|
else:
|
|
LOGIN_URL = settings.LOGIN_URL
|
|
|
|
|
|
def home(request):
|
|
"""
|
|
Displays a list of messages to be translated
|
|
"""
|
|
|
|
def fix_nls(in_,out_):
|
|
"""Fixes submitted translations by filtering carriage returns and pairing
|
|
newlines at the begging and end of the translated string with the original
|
|
"""
|
|
if 0 == len(in_) or 0 == len(out_):
|
|
return out_
|
|
|
|
if "\r" in out_ and "\r" not in in_:
|
|
out_=out_.replace("\r",'')
|
|
|
|
if "\n" == in_[0] and "\n" != out_[0]:
|
|
out_ = "\n" + out_
|
|
elif "\n" != in_[0] and "\n" == out_[0]:
|
|
out_ = out_.lstrip()
|
|
if "\n" == in_[-1] and "\n" != out_[-1]:
|
|
out_ = out_ + "\n"
|
|
elif "\n" != in_[-1] and "\n" == out_[-1]:
|
|
out_ = out_.rstrip()
|
|
return out_
|
|
|
|
version = rosetta.get_version(True)
|
|
if 'rosetta_i18n_fn' in request.session:
|
|
rosetta_i18n_fn=request.session.get('rosetta_i18n_fn')
|
|
rosetta_i18n_app = get_app_name(rosetta_i18n_fn)
|
|
rosetta_i18n_pofile = request.session.get('rosetta_i18n_pofile')
|
|
rosetta_i18n_lang_code = request.session['rosetta_i18n_lang_code']
|
|
rosetta_i18n_lang_bidi = (rosetta_i18n_lang_code in settings.LANGUAGES_BIDI)
|
|
rosetta_i18n_write = request.session.get('rosetta_i18n_write', True)
|
|
|
|
if 'filter' in request.GET:
|
|
if request.GET.get('filter') in ('untranslated', 'translated', 'fuzzy', 'all'):
|
|
filter_ = request.GET.get('filter')
|
|
request.session['rosetta_i18n_filter'] = filter_
|
|
return HttpResponseRedirect(reverse('rosetta-home'))
|
|
|
|
rosetta_i18n_filter = request.session.get('rosetta_i18n_filter', 'all')
|
|
|
|
if '_next' in request.POST:
|
|
rx=re.compile(r'^m_([0-9]+)')
|
|
rx_plural=re.compile(r'^m_([0-9]+)_([0-9]+)')
|
|
file_change = False
|
|
for k in request.POST.keys():
|
|
if rx_plural.match(k):
|
|
id=int(rx_plural.match(k).groups()[0])
|
|
idx=int(rx_plural.match(k).groups()[1])
|
|
rosetta_i18n_pofile[id].msgstr_plural[str(idx)] = fix_nls(rosetta_i18n_pofile[id].msgid_plural[idx], request.POST.get(k))
|
|
file_change = True
|
|
elif rx.match(k):
|
|
id=int(rx.match(k).groups()[0])
|
|
rosetta_i18n_pofile[id].msgstr = fix_nls(rosetta_i18n_pofile[id].msgid, request.POST.get(k))
|
|
file_change = True
|
|
|
|
if file_change and 'fuzzy' in rosetta_i18n_pofile[id].flags and not request.POST.get('f_%d' %id, False):
|
|
rosetta_i18n_pofile[id].flags.remove('fuzzy')
|
|
elif file_change and 'fuzzy' not in rosetta_i18n_pofile[id].flags and request.POST.get('f_%d' %id, False):
|
|
rosetta_i18n_pofile[id].flags.append('fuzzy')
|
|
|
|
if file_change and rosetta_i18n_write:
|
|
|
|
try:
|
|
rosetta_i18n_pofile.metadata['Last-Translator'] = unicodedata.normalize('NFKD', u"%s %s <%s>" %(request.user.first_name,request.user.last_name,request.user.email)).encode('ascii', 'ignore')
|
|
rosetta_i18n_pofile.metadata['X-Translated-Using'] = u"django-rosetta %s" % rosetta.get_version(False)
|
|
rosetta_i18n_pofile.metadata['PO-Revision-Date'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M%z')
|
|
except UnicodeDecodeError:
|
|
pass
|
|
try:
|
|
rosetta_i18n_pofile.save()
|
|
rosetta_i18n_pofile.save_as_mofile(rosetta_i18n_fn.replace('.po','.mo'))
|
|
|
|
# Try auto-reloading via the WSGI daemon mode reload mechanism
|
|
if rosetta_settings.WSGI_AUTO_RELOAD and \
|
|
request.environ.has_key('mod_wsgi.process_group') and \
|
|
request.environ.get('mod_wsgi.process_group',None) and \
|
|
request.environ.has_key('SCRIPT_FILENAME') and \
|
|
int(request.environ.get('mod_wsgi.script_reloading', '0')):
|
|
try:
|
|
os.utime(request.environ.get('SCRIPT_FILENAME'), None)
|
|
except OSError:
|
|
pass
|
|
|
|
except:
|
|
request.session['rosetta_i18n_write'] = False
|
|
|
|
request.session['rosetta_i18n_pofile']=rosetta_i18n_pofile
|
|
|
|
# Retain query arguments
|
|
query_arg = ''
|
|
if 'query' in request.REQUEST:
|
|
query_arg = '?query=%s' %request.REQUEST.get('query')
|
|
if 'page' in request.GET:
|
|
if query_arg:
|
|
query_arg = query_arg + '&'
|
|
else:
|
|
query_arg = '?'
|
|
query_arg = query_arg + 'page=%d' % int(request.GET.get('page'))
|
|
|
|
|
|
return HttpResponseRedirect(reverse('rosetta-home') + iri_to_uri(query_arg))
|
|
|
|
|
|
rosetta_i18n_lang_name = _(request.session.get('rosetta_i18n_lang_name'))
|
|
rosetta_i18n_lang_code = request.session.get('rosetta_i18n_lang_code')
|
|
|
|
if 'query' in request.REQUEST and request.REQUEST.get('query','').strip():
|
|
query=request.REQUEST.get('query').strip()
|
|
rx=re.compile(query, re.IGNORECASE)
|
|
paginator = Paginator([e for e in rosetta_i18n_pofile if rx.search(smart_unicode(e.msgstr)+smart_unicode(e.msgid)+u''.join([o[0] for o in e.occurrences]))], rosetta_settings.MESSAGES_PER_PAGE)
|
|
else:
|
|
if rosetta_i18n_filter == 'untranslated':
|
|
paginator = Paginator(rosetta_i18n_pofile.untranslated_entries(), rosetta_settings.MESSAGES_PER_PAGE)
|
|
elif rosetta_i18n_filter == 'translated':
|
|
paginator = Paginator(rosetta_i18n_pofile.translated_entries(), rosetta_settings.MESSAGES_PER_PAGE)
|
|
elif rosetta_i18n_filter == 'fuzzy':
|
|
paginator = Paginator(rosetta_i18n_pofile.fuzzy_entries(), rosetta_settings.MESSAGES_PER_PAGE)
|
|
else:
|
|
paginator = Paginator([e for e in rosetta_i18n_pofile if not e.obsolete], rosetta_settings.MESSAGES_PER_PAGE)
|
|
|
|
if 'page' in request.GET and int(request.GET.get('page')) <= paginator.num_pages and int(request.GET.get('page')) > 0:
|
|
page = int(request.GET.get('page'))
|
|
else:
|
|
page = 1
|
|
messages = paginator.page(page).object_list
|
|
if rosetta_settings.MAIN_LANGUAGE and rosetta_settings.MAIN_LANGUAGE != rosetta_i18n_lang_code:
|
|
|
|
main_language = None
|
|
for language in settings.LANGUAGES:
|
|
if language[0] == rosetta_settings.MAIN_LANGUAGE:
|
|
main_language = _(language[1])
|
|
break
|
|
|
|
fl = ("/%s/" % rosetta_settings.MAIN_LANGUAGE).join(rosetta_i18n_fn.split("/%s/" % rosetta_i18n_lang_code))
|
|
po = pofile(fl)
|
|
|
|
main_messages = []
|
|
for message in messages:
|
|
message.main_lang = po.find(message.msgid).msgstr
|
|
|
|
needs_pagination = paginator.num_pages > 1
|
|
if needs_pagination:
|
|
if paginator.num_pages >= 10:
|
|
page_range = pagination_range(1, paginator.num_pages, page)
|
|
else:
|
|
page_range = range(1,1+paginator.num_pages)
|
|
ADMIN_MEDIA_PREFIX = settings.ADMIN_MEDIA_PREFIX
|
|
ENABLE_TRANSLATION_SUGGESTIONS = rosetta_settings.ENABLE_TRANSLATION_SUGGESTIONS
|
|
|
|
return render_to_response('rosetta/pofile.html', locals(), context_instance=RequestContext(request))
|
|
|
|
|
|
else:
|
|
return list_languages(request)
|
|
home=user_passes_test(lambda user:can_translate(user),LOGIN_URL)(home)
|
|
home=never_cache(home)
|
|
|
|
|
|
def download_file(request):
|
|
import zipfile, os
|
|
from StringIO import StringIO
|
|
# original filename
|
|
rosetta_i18n_fn=request.session.get('rosetta_i18n_fn', None)
|
|
# in-session modified catalog
|
|
rosetta_i18n_pofile = request.session.get('rosetta_i18n_pofile', None)
|
|
# language code
|
|
rosetta_i18n_lang_code = request.session.get('rosetta_i18n_lang_code', None)
|
|
|
|
if not rosetta_i18n_lang_code or not rosetta_i18n_pofile or not rosetta_i18n_fn:
|
|
return HttpResponseRedirect(reverse('rosetta-home'))
|
|
try:
|
|
if len(rosetta_i18n_fn.split('/')) >= 5:
|
|
offered_fn = '_'.join(rosetta_i18n_fn.split('/')[-5:])
|
|
else:
|
|
offered_fn = rosetta_i18n_fn.split('/')[-1]
|
|
po_fn = str(rosetta_i18n_fn.split('/')[-1])
|
|
mo_fn = str(po_fn.replace('.po','.mo')) # not so smart, huh
|
|
zipdata = StringIO()
|
|
zipf = zipfile.ZipFile(zipdata, mode="w")
|
|
zipf.writestr(po_fn, str(rosetta_i18n_pofile))
|
|
zipf.writestr(mo_fn, rosetta_i18n_pofile.to_binary())
|
|
zipf.close()
|
|
zipdata.seek(0)
|
|
|
|
response = HttpResponse(zipdata.read())
|
|
response['Content-Disposition'] = 'attachment; filename=%s.%s.zip' %(offered_fn,rosetta_i18n_lang_code)
|
|
response['Content-Type'] = 'application/x-zip'
|
|
return response
|
|
except Exception, e:
|
|
return HttpResponseRedirect(reverse('rosetta-home'))
|
|
|
|
download_file=user_passes_test(lambda user:can_translate(user),LOGIN_URL)(download_file)
|
|
download_file=never_cache(download_file)
|
|
|
|
|
|
|
|
def list_languages(request):
|
|
"""
|
|
Lists the languages for the current project, the gettext catalog files
|
|
that can be translated and their translation progress
|
|
"""
|
|
languages = []
|
|
do_django = 'django' in request.GET
|
|
do_rosetta = 'rosetta' in request.GET
|
|
has_pos = False
|
|
for language in settings.LANGUAGES:
|
|
pos = find_pos(language[0],include_djangos=do_django,include_rosetta=do_rosetta)
|
|
has_pos = has_pos or len(pos)
|
|
languages.append(
|
|
(language[0],
|
|
_(language[1]),
|
|
[(get_app_name(l), os.path.realpath(l), pofile(l)) for l in pos],
|
|
)
|
|
)
|
|
ADMIN_MEDIA_PREFIX = settings.ADMIN_MEDIA_PREFIX
|
|
version = rosetta.get_version(True)
|
|
return render_to_response('rosetta/languages.html', locals(), context_instance=RequestContext(request))
|
|
list_languages=user_passes_test(lambda user:can_translate(user),LOGIN_URL)(list_languages)
|
|
list_languages=never_cache(list_languages)
|
|
|
|
def get_app_name(path):
|
|
app = path.split("/locale")[0].split("/")[-1]
|
|
return app
|
|
|
|
def lang_sel(request,langid,idx):
|
|
"""
|
|
Selects a file to be translated
|
|
"""
|
|
if langid not in [l[0] for l in settings.LANGUAGES]:
|
|
raise Http404
|
|
else:
|
|
|
|
do_django = 'django' in request.GET
|
|
do_rosetta = 'rosetta' in request.GET
|
|
|
|
file_ = find_pos(langid,include_djangos=do_django,include_rosetta=do_rosetta)[int(idx)]
|
|
|
|
request.session['rosetta_i18n_lang_code'] = langid
|
|
request.session['rosetta_i18n_lang_name'] = unicode([l[1] for l in settings.LANGUAGES if l[0] == langid][0])
|
|
request.session['rosetta_i18n_fn'] = file_
|
|
po = pofile(file_)
|
|
for i in range(len(po)):
|
|
po[i].id = i
|
|
|
|
request.session['rosetta_i18n_pofile'] = po
|
|
try:
|
|
os.utime(file_,None)
|
|
request.session['rosetta_i18n_write'] = True
|
|
except OSError:
|
|
request.session['rosetta_i18n_write'] = False
|
|
|
|
return HttpResponseRedirect(reverse('rosetta-home'))
|
|
lang_sel=user_passes_test(lambda user:can_translate(user),LOGIN_URL)(lang_sel)
|
|
lang_sel=never_cache(lang_sel)
|
|
|
|
def can_translate(user):
|
|
if not user.is_authenticated():
|
|
return False
|
|
elif user.is_superuser:
|
|
return True
|
|
else:
|
|
try:
|
|
from django.contrib.auth.models import Group
|
|
translators = Group.objects.get(name='translators')
|
|
return translators in user.groups.all()
|
|
except Group.DoesNotExist:
|
|
return False
|