Commit 7c22f2c8 authored by Michal Čihař's avatar Michal Čihař

Merge branch 'master' into bootstrap

parents a2ebe9db 4fa82270
......@@ -26,8 +26,10 @@ PIL or Pillow library
https://python-pillow.github.io/
lxml (>= 3.1.0)
http://lxml.de/
South (>= 1.0)
South (>= 1.0) (needed for Django < 1.7)
http://south.aeracode.org/
dateutil
http://labix.org/python-dateutil
libravatar (optional for federated avatar support)
https://pypi.python.org/pypi/pyLibravatar
PyICU (optional for proper sorting of strings)
......
......@@ -14,6 +14,7 @@ Released on ? 2014.
* Fixed generating mo files in certain cases.
* Added support for GitLab notifications.
* Added support for disabling translation suggestions.
* Django 1.7 support.
weblate 1.9
-----------
......
......@@ -2,3 +2,4 @@
PyICU
pyLibravatar
babel
South>=1.0
......@@ -23,7 +23,7 @@ from weblate.trans.scripts import get_script_name
import os
def get(name, default):
def getvalue(name, default):
"""
Returns setting from django settings with default value.
"""
......@@ -31,75 +31,75 @@ def get(name, default):
# Weblate installation root
BASE_DIR = get('BASE_DIR', os.path.dirname(os.path.abspath(__file__)))
BASE_DIR = getvalue('BASE_DIR', os.path.dirname(os.path.abspath(__file__)))
# Machine translation API keys
# Apertium Web Service, register at http://api.apertium.org/register.jsp
MT_APERTIUM_KEY = get('MT_APERTIUM_KEY', None)
MT_APERTIUM_KEY = getvalue('MT_APERTIUM_KEY', None)
# Microsoft Translator service, register at
# https://datamarket.azure.com/developer/applications/
MT_MICROSOFT_ID = get('MT_MICROSOFT_ID', None)
MT_MICROSOFT_SECRET = get('MT_MICROSOFT_SECRET', None)
MT_MICROSOFT_ID = getvalue('MT_MICROSOFT_ID', None)
MT_MICROSOFT_SECRET = getvalue('MT_MICROSOFT_SECRET', None)
# MyMemory identification email, see
# http://mymemory.translated.net/doc/spec.php
MT_MYMEMORY_EMAIL = get('MT_MYMEMORY_EMAIL', None)
MT_MYMEMORY_EMAIL = getvalue('MT_MYMEMORY_EMAIL', None)
# Optional MyMemory credentials to access private translation memory
MT_MYMEMORY_USER = get('MT_MYMEMORY_USER', None)
MT_MYMEMORY_KEY = get('MT_MYMEMORY_KEY', None)
MT_MYMEMORY_USER = getvalue('MT_MYMEMORY_USER', None)
MT_MYMEMORY_KEY = getvalue('MT_MYMEMORY_KEY', None)
# Google API key for Google Translate API
MT_GOOGLE_KEY = get('MT_GOOGLE_KEY', None)
MT_GOOGLE_KEY = getvalue('MT_GOOGLE_KEY', None)
# tmserver URL
MT_TMSERVER = get('MT_TMSERVER', None)
MT_TMSERVER = getvalue('MT_TMSERVER', None)
# Path where git repositories are stored, it needs to be writable
GIT_ROOT = get('GIT_ROOT', os.path.join(BASE_DIR, 'repos'))
GIT_ROOT = getvalue('GIT_ROOT', os.path.join(BASE_DIR, 'repos'))
# Title of site to use
SITE_TITLE = get('SITE_TITLE', 'Weblate')
SITE_TITLE = getvalue('SITE_TITLE', 'Weblate')
# Whether to offer hosting
OFFER_HOSTING = get('OFFER_HOSTING', False)
OFFER_HOSTING = getvalue('OFFER_HOSTING', False)
# Demo server tweaks
DEMO_SERVER = get('DEMO_SERVER', False)
DEMO_SERVER = getvalue('DEMO_SERVER', False)
# Enable remote hooks
ENABLE_HOOKS = get('ENABLE_HOOKS', True)
ENABLE_HOOKS = getvalue('ENABLE_HOOKS', True)
# Enable sharing
ENABLE_SHARING = get('ENABLE_SHARING', True)
ENABLE_SHARING = getvalue('ENABLE_SHARING', True)
# Whether to run hooks in background
BACKGROUND_HOOKS = get('BACKGROUND_HOOKS', True)
BACKGROUND_HOOKS = getvalue('BACKGROUND_HOOKS', True)
# Number of nearby messages to show in each direction
NEARBY_MESSAGES = get('NEARBY_MESSAGES', 5)
NEARBY_MESSAGES = getvalue('NEARBY_MESSAGES', 5)
# Minimal number of similar messages to show
SIMILAR_MESSAGES = get('SIMILAR_MESSAGES', 5)
SIMILAR_MESSAGES = getvalue('SIMILAR_MESSAGES', 5)
# Enable lazy commits
LAZY_COMMITS = get('LAZY_COMMITS', True)
LAZY_COMMITS = getvalue('LAZY_COMMITS', True)
# Offload indexing
OFFLOAD_INDEXING = get('OFFLOAD_INDEXING', False)
OFFLOAD_INDEXING = getvalue('OFFLOAD_INDEXING', False)
# Translation locking
AUTO_LOCK = get('AUTO_LOCK', True)
AUTO_LOCK_TIME = get('AUTO_LOCK_TIME', 60)
LOCK_TIME = get('LOCK_TIME', 15 * 60)
AUTO_LOCK = getvalue('AUTO_LOCK', True)
AUTO_LOCK_TIME = getvalue('AUTO_LOCK_TIME', 60)
LOCK_TIME = getvalue('LOCK_TIME', 15 * 60)
# Where to put Whoosh index
WHOOSH_INDEX = get('WHOOSH_INDEX', os.path.join(BASE_DIR, 'whoosh-index'))
WHOOSH_INDEX = getvalue('WHOOSH_INDEX', os.path.join(BASE_DIR, 'whoosh-index'))
# List of quality checks
CHECK_LIST = get('CHECK_LIST', (
CHECK_LIST = getvalue('CHECK_LIST', (
'weblate.trans.checks.same.SameCheck',
'weblate.trans.checks.chars.BeginNewlineCheck',
'weblate.trans.checks.chars.EndNewlineCheck',
......@@ -126,14 +126,14 @@ CHECK_LIST = get('CHECK_LIST', (
))
# List of automatic fixups
AUTOFIX_LIST = get('AUTOFIX_LIST', (
AUTOFIX_LIST = getvalue('AUTOFIX_LIST', (
'weblate.trans.autofixes.whitespace.SameBookendingWhitespace',
'weblate.trans.autofixes.chars.ReplaceTrailingDotsWithEllipsis',
'weblate.trans.autofixes.chars.RemoveZeroSpace',
))
# List of machine translations
MACHINE_TRANSLATION_SERVICES = get('MACHINE_TRANSLATION_SERVICES', (
MACHINE_TRANSLATION_SERVICES = getvalue('MACHINE_TRANSLATION_SERVICES', (
'weblate.trans.machine.weblatetm.WeblateSimilarTranslation',
'weblate.trans.machine.weblatetm.WeblateTranslation',
))
......@@ -142,43 +142,45 @@ MACHINE_TRANSLATION_SERVICES = get('MACHINE_TRANSLATION_SERVICES', (
MACHINE_TRANSLATION_ENABLED = len(MACHINE_TRANSLATION_SERVICES) > 0
# List of scripts to use in custom processing
PRE_COMMIT_SCRIPTS = get('PRE_COMMIT_SCRIPTS', ())
PRE_COMMIT_SCRIPTS = getvalue('PRE_COMMIT_SCRIPTS', ())
SCRIPT_CHOICES = [
(script, get_script_name(script)) for script in PRE_COMMIT_SCRIPTS
] + [('', '')]
# Font for charts and widgets
TTF_PATH = get('TTF_PATH', os.path.join(BASE_DIR, 'ttf'))
TTF_PATH = getvalue('TTF_PATH', os.path.join(BASE_DIR, 'ttf'))
# Anonymous user name
ANONYMOUS_USER_NAME = get('ANONYMOUS_USER_NAME', 'anonymous')
ANONYMOUS_USER_NAME = getvalue('ANONYMOUS_USER_NAME', 'anonymous')
# Enable registrations
REGISTRATION_OPEN = get('REGISTRATION_OPEN', True)
REGISTRATION_OPEN = getvalue('REGISTRATION_OPEN', True)
# Captcha for registrations
REGISTRATION_CAPTCHA = get('REGISTRATION_CAPTCHA', True)
REGISTRATION_CAPTCHA = getvalue('REGISTRATION_CAPTCHA', True)
# Source language
SOURCE_LANGUAGE = get('SOURCE_LANGUAGE', 'en')
SOURCE_LANGUAGE = getvalue('SOURCE_LANGUAGE', 'en')
# Self advertisement
SELF_ADVERTISEMENT = get('SELF_ADVERTISEMENT', False)
SELF_ADVERTISEMENT = getvalue('SELF_ADVERTISEMENT', False)
# Use simple language codes for default language/country combinations
SIMPLIFY_LANGUAGES = get('SIMPLIFY_LANGUAGES', True)
SIMPLIFY_LANGUAGES = getvalue('SIMPLIFY_LANGUAGES', True)
# Disable avatars
ENABLE_AVATARS = get('ENABLE_AVATARS', True)
ENABLE_AVATARS = getvalue('ENABLE_AVATARS', True)
# Avatar URL prefix
AVATAR_URL_PREFIX = get('AVATAR_URL_PREFIX', 'https://seccdn.libravatar.org/')
AVATAR_URL_PREFIX = getvalue(
'AVATAR_URL_PREFIX', 'https://seccdn.libravatar.org/'
)
# Avatar fallback image
# See http://wiki.libravatar.org/api/ for available choices
AVATAR_DEFAULT_IMAGE = get('AVATAR_DEFAULT_IMAGE', 'identicon')
AVATAR_DEFAULT_IMAGE = getvalue('AVATAR_DEFAULT_IMAGE', 'identicon')
# Is the site using https
ENABLE_HTTPS = get('ENABLE_HTTPS', False)
ENABLE_HTTPS = getvalue('ENABLE_HTTPS', False)
ENABLE_WHITEBOARD = get('ENABLE_WHITEBOARD', False)
ENABLE_WHITEBOARD = getvalue('ENABLE_WHITEBOARD', False)
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load translations %}
{% load cycle from future %}
{% block title %}{% trans "Performance report" %}{% endblock %}
......@@ -24,7 +25,7 @@
</thead>
<tbody>
{% for check in checks %}
<tr class="row{% cycle 1,2 %} {{ check.3 }}">
<tr class="row{% cycle '1' '2' %} {{ check.3 }}">
<td>{{ check.0 }}</td>
<td>{% admin_boolean_icon check.1 %}</td>
<td><a href="{% documentation "admin/install" check.2 %}">{% trans "Documentation" %}</a></td>
......@@ -47,7 +48,7 @@
</thead>
<tbody>
{% for error in errors %}
<tr class="row{% cycle 1,2 %} {{ check.3 }}">
<tr class="row{% cycle '1' '2' %} {{ check.3 }}">
<td>{{ error.name }}</td>
<td><pre>{{ error.message }}</pre></td>
</tr>
......
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load cycle from future %}
{% block title %}{% trans "SSH keys" %}{% endblock %}
......@@ -44,7 +45,7 @@
</thead>
<tbody>
{% for key in host_keys %}
<tr class="row{% cycle 1,2 %}"><td>{{ key.0 }}</td><td>{{ key.1 }}</td><td>{{ key.2 }}</td></tr>
<tr class="row{% cycle '1' '2' %}"><td>{{ key.0 }}</td><td>{{ key.1 }}</td><td>{{ key.2 }}</td></tr>
{% endfor %}
</tbody>
</table>
......
......@@ -3,17 +3,17 @@
{% load translations %}
{% block form_top %}
{% if opts.module_name == 'project' or opts.module_name == 'subproject' or opts.module_name == 'advertisement' or opts.module_name == 'whiteboardmessage' %}
{% if opts.module_name == 'advertisement' %}
{% if opts.model_name == 'project' or opts.model_name == 'subproject' or opts.model_name == 'advertisement' or opts.model_name == 'whiteboardmessage' %}
{% if opts.model_name == 'advertisement' %}
{% doc_url 'admin/advertisement' as url %}
{% else %}
{% doc_url 'admin/projects' opts.module_name as url %}
{% doc_url 'admin/projects' opts.model_name as url %}
{% endif %}
<p>{% blocktrans %}Required fields are marked as bold, you can find more information in the <a href="{{ url }}">documentation</a>.{% endblocktrans %}</p>
{% else %}
<p class="errornote">{% blocktrans %}Do not change this object here, please use Weblate interface instead.{% endblocktrans %}</p>
{% endif %}
{% if add and opts.module_name == 'subproject' %}
{% if add and opts.model_name == 'subproject' %}
{% doc_url 'admin/projects' 'import-speed' as url %}
<p>{% blocktrans %}Importing a new translation can take some time, please check <a href="{{ url }}">our documentation</a> for information on how to improve this.{% endblocktrans %}</p>
{% endif %}
......
......@@ -199,6 +199,16 @@ def get_versions():
'1.1.6',
))
name = 'dateutil'
url = 'http://labix.org/python-dateutil'
mod = get_version_module('dateutil', name, url)
result.append((
name,
url,
mod.__version__,
'1.0'
))
name = 'lxml'
url = 'http://lxml.de/'
mod = get_version_module('lxml.etree', name, url)
......
......@@ -76,3 +76,12 @@ class VCSGitTest(RepoTestCase):
def test_needs_commit(self):
repo = GitRepository.clone(self.repo_path, self._tempdir)
self.assertFalse(repo.needs_commit())
def test_revision_info(self):
repo = GitRepository.clone(self.repo_path, self._tempdir)
info = repo.get_revision_info(repo.last_revision)
self.assertTrue('summary' in info)
self.assertTrue('author' in info)
self.assertTrue('authordate' in info)
self.assertTrue('commit' in info)
self.assertTrue('commitdate' in info)
......@@ -21,6 +21,7 @@
Minimal distributed version control system abstraction for Weblate needs.
"""
import subprocess
from dateutil import parser
class RepositoryException(Exception):
......@@ -32,6 +33,15 @@ class RepositoryException(Exception):
class Repository(object):
"""
Basic repository object.
Currently missing methods:
- repository configuration (SubProject.configure_repo)
- branch configuration (SubProject.configure_branch)
- needs merge/push (SubProject.git_needs_merge/push)
- get object hash (Translation.get_git_blob_hash)
- commit (Translation.__git_commit)
- configuration (Translation.__configure_committer)
"""
_last_revision = None
_last_remote_revision = None
......@@ -50,7 +60,7 @@ class Repository(object):
def _popen(cls, args, cwd=None):
if args is None:
raise RepositoryException('Not supported functionality')
args.insert(0, cls._cmd)
args = [cls._cmd] + args
process = subprocess.Popen(
args,
cwd=cwd,
......@@ -133,6 +143,12 @@ class Repository(object):
"""
raise NotImplementedError()
def get_revision_info(self, revision):
"""
Returns dictionary with detailed revision information.
"""
raise NotImplementedError()
class GitRepository(Repository):
"""
......@@ -171,3 +187,37 @@ class GitRepository(Repository):
Checks whether repository needs commit.
"""
return self._execute(['status', '--porcelain']) != ''
def get_revision_info(self, revision):
"""
Returns dictionary with detailed revision information.
"""
text = self._execute(
['show', '--format=fuller', '--date=rfc', '--no-patch', revision]
)
result = {}
message = []
header = True
for line in text.splitlines():
if header:
if not line:
header = False
elif line.startswith('commit'):
continue
else:
name, value = line.strip().split(':', 1)
if 'Date' in name:
result[name.lower()] = parser.parse(value.strip())
else:
result[name.lower()] = value.strip()
else:
message.append(line.strip())
result['message'] = '\n'.join(message)
result['summary'] = message[0]
return result
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment