Permalink
Browse files

Initial translation support. Not functional yet.

  • Loading branch information...
1 parent 011896a commit 25a6101f4b0032168c244ea12b411e15f9375cfd @ericholscher ericholscher committed Mar 18, 2013
@@ -92,3 +92,39 @@
('python', _('Python 2.x')),
('python3', _('Python 3.x')),
)
+
+# Via http://sphinx-doc.org/latest/config.html#confval-language
+LANGUAGES = (
+ ("bn", "Bengali"),
+ ("ca", "Catalan"),
+ ("cs", "Czech"),
+ ("da", "Danish"),
+ ("de", "German"),
+ ("en", "English"),
+ ("es", "Spanish"),
+ ("et", "Estonian"),
+ ("eu", "Basque"),
+ ("fa", "Iranian"),
+ ("fi", "Finnish"),
+ ("fr", "French"),
+ ("hr", "Croatian"),
+ ("hu", "Hungarian"),
+ ("it", "Italian"),
+ ("ja", "Japanese"),
+ ("ko", "Korean"),
+ ("lt", "Lithuanian"),
+ ("lv", "Latvian"),
+ ("ne", "Nepali"),
+ ("nl", "Dutch"),
+ ("pl", "Polish"),
+ ("ru", "Russian"),
+ ("sk", "Slovak"),
+ ("sl", "Slovenian"),
+ ("sv", "Swedish"),
+ ("tr", "Turkish"),
+ ("nb_NO", "Norwegian Bokmal"),
+ ("pt_BR", "Brazilian Portuguese"),
+ ("uk_UA", "Ukrainian"),
+ ("zh_CN", "Simplified Chinese"),
+ ("zh_TW", "Traditional Chinese"),
+)
@@ -31,12 +31,12 @@ class ImportProjectForm(ProjectForm):
python_interpreter = forms.ChoiceField(
choices=constants.PYTHON_CHOICES, initial='python',
help_text=_("(Beta) The Python interpreter used to create the virtual environment."))
-
+
class Meta:
model = Project
fields = (
# Important
- 'name', 'repo', 'repo_type', 'description',
+ 'name', 'repo', 'repo_type', 'description', 'language',
# Not as important
'project_url', 'tags', 'default_branch', 'default_version', 'conf_py_file',
# Privacy
@@ -235,3 +235,23 @@ def clean_email(self):
def save(self):
project = self.project.emailhook_notifications.add(self.email)
return self.project
+
+class TranslationForm(forms.Form):
+ project = forms.CharField()
+
+ def __init__(self, *args, **kwargs):
+ self.parent = kwargs.pop('parent', None)
+ super(TranslationForm, self).__init__(*args, **kwargs)
+
+ def clean_project(self):
+ subproject_name = self.cleaned_data['project']
+ subproject_qs = Project.objects.filter(name=subproject_name)
+ if not subproject_qs.exists():
+ raise forms.ValidationError(_("Project %(name)s does not exist") % {'name': subproject_name})
+ self.subproject = subproject_qs[0]
+ return subproject_name
+
+ def save(self):
+ project = self.parent.translations.add(self.subproject)
+ return project
+
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Project.language'
+ db.add_column('projects_project', 'language',
+ self.gf('django.db.models.fields.CharField')(default='en', max_length=20),
+ keep_default=False)
+
+ # Adding field 'Project.main_language_project'
+ db.add_column('projects_project', 'main_language_project',
+ self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='languages', null=True, to=orm['projects.Project']),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Project.language'
+ db.delete_column('projects_project', 'language')
+
+ # Deleting field 'Project.main_language_project'
+ db.delete_column('projects_project', 'main_language_project_id')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'builds.version': {
+ 'Meta': {'ordering': "['-verbose_name']", 'unique_together': "[('project', 'slug')]", 'object_name': 'Version'},
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'built': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'privacy_level': ('django.db.models.fields.CharField', [], {'default': "'public'", 'max_length': '20'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 'to': "orm['projects.Project']"}),
+ 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'uploaded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'verbose_name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'projects.emailhook': {
+ 'Meta': {'object_name': 'EmailHook'},
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailhook_notifications'", 'to': "orm['projects.Project']"})
+ },
+ 'projects.importedfile': {
+ 'Meta': {'object_name': 'ImportedFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'md5': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'imported_files'", 'to': "orm['projects.Project']"}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'imported_filed'", 'null': 'True', 'to': "orm['builds.Version']"})
+ },
+ 'projects.project': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'Project'},
+ 'analytics_code': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'conf_py_file': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}),
+ 'copyright': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'crate_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'default_branch': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'default_version': ('django.db.models.fields.CharField', [], {'default': "'latest'", 'max_length': '255'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'django_packages_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'documentation_type': ('django.db.models.fields.CharField', [], {'default': "'sphinx'", 'max_length': '20'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '20'}),
+ 'main_language_project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'languages'", 'null': 'True', 'to': "orm['projects.Project']"}),
+ 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'privacy_level': ('django.db.models.fields.CharField', [], {'default': "'public'", 'max_length': '20'}),
+ 'project_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
+ 'pub_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'python_interpreter': ('django.db.models.fields.CharField', [], {'default': "'python'", 'max_length': '20'}),
+ 'related_projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['projects.Project']", 'null': 'True', 'through': "orm['projects.ProjectRelationship']", 'blank': 'True'}),
+ 'repo': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'repo_type': ('django.db.models.fields.CharField', [], {'default': "'git'", 'max_length': '10'}),
+ 'requirements_file': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'skip': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+ 'suffix': ('django.db.models.fields.CharField', [], {'default': "'.rst'", 'max_length': '10'}),
+ 'theme': ('django.db.models.fields.CharField', [], {'default': "'default'", 'max_length': '20'}),
+ 'use_system_packages': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'use_virtualenv': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'projects'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'version_privacy_level': ('django.db.models.fields.CharField', [], {'default': "'public'", 'max_length': '20'})
+ },
+ 'projects.projectrelationship': {
+ 'Meta': {'object_name': 'ProjectRelationship'},
+ 'child': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'superprojects'", 'to': "orm['projects.Project']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subprojects'", 'to': "orm['projects.Project']"})
+ },
+ 'projects.webhook': {
+ 'Meta': {'object_name': 'WebHook'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'webhook_notifications'", 'to': "orm['projects.Project']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'taggit.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
+ },
+ 'taggit.taggeditem': {
+ 'Meta': {'object_name': 'TaggedItem'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
+ }
+ }
+
+ complete_apps = ['projects']
@@ -113,7 +113,7 @@ class Project(models.Model):
help_text=_('Type of documentation you are building. <a href="http://sphinx.pocoo.org/builders.html#sphinx.builders.html.DirectoryHTMLBuilder">More info</a>.'))
analytics_code = models.CharField(_('Analytics code'), max_length=50, null=True, blank=True, help_text=_("Google Analytics Tracking ID (ex. UA-22345342-1). This may slow down your page loads."))
- #Other model data.
+ # Other model data.
path = models.CharField(_('Path'), help_text=_("The directory where conf.py lives"),
max_length=255, editable=False)
conf_py_file = models.CharField(_('Python configuration file'),
@@ -124,11 +124,7 @@ class Project(models.Model):
use_virtualenv = models.BooleanField(_('Use virtualenv'),
help_text=_("Install your project inside a virtualenv using setup.py install"))
- #
- # this model attribute hold the python interpreter used to create the
- # virtual environment (therefore the interpreter used on the virtual
- # environment)
- #
+ # This model attribute holds the python interpreter used to create the virtual environment
python_interpreter = models.CharField(_('Python Interpreter'),
max_length=20,
choices=constants.PYTHON_CHOICES,
@@ -146,9 +142,14 @@ class Project(models.Model):
choices=constants.PRIVACY_CHOICES, default='public',
help_text=_("(Beta) Default level of privacy you want on built versions of documentation."))
- #Subprojects
+ # Subprojects
related_projects = models.ManyToManyField('self', verbose_name=_('Related projects'), blank=True, null=True, symmetrical=False, through=ProjectRelationship)
+ # Language bits
+ language = models.CharField('Language', max_length=20, default='en', help_text="The language the project documentation is rendered in", choices=constants.LANGUAGES)
+ # A subproject pointed at it's main language, so it can be tracked
+ main_language_project = models.ForeignKey('self', related_name='translations', blank=True, null=True)
+
tags = TaggableManager(blank=True)
objects = ProjectManager()
@@ -73,4 +73,12 @@
'project_notifications_delete',
name='projects_notification_delete'
),
+ url(r'^(?P<project_slug>[-\w]+)/translations/$',
+ 'project_translations',
+ name='projects_translations'
+ ),
+ url(r'^(?P<project_slug>[-\w]+)/translations/delete/(?P<child_slug>[-\w]+)/$',
+ 'project_translations_delete',
+ name='projects_translations_delete'
+ ),
)
@@ -18,7 +18,7 @@
from builds.models import Version
from projects.forms import (ImportProjectForm, build_versions_form,
build_upload_html_form, SubprojectForm,
- UserForm, EmailHookForm)
+ UserForm, EmailHookForm, TranslationForm)
from projects.models import Project, EmailHook, WebHook
from projects.tasks import unzip_files
from projects import constants
@@ -342,3 +342,29 @@ def project_notifications_delete(request, project_slug):
notification.delete()
project_dashboard = reverse('projects_notifications', args=[project.slug])
return HttpResponseRedirect(project_dashboard)
+
+@login_required
+def project_translations(request, project_slug):
+ project = get_object_or_404(request.user.projects.live(), slug=project_slug)
+ form = TranslationForm(data=request.POST or None, parent=project)
+
+ if request.method == 'POST' and form.is_valid():
+ form.save()
+ project_dashboard = reverse('projects_translations', args=[project.slug])
+ return HttpResponseRedirect(project_dashboard)
+
+ lang_projects = project.translations.all()
+
+ return render_to_response(
+ 'projects/project_translations.html',
+ {'form': form, 'project': project, 'lang_projects': lang_projects},
+ context_instance=RequestContext(request)
+ )
+
+@login_required
+def project_translations_delete(request, project_slug, child_slug):
+ project = get_object_or_404(request.user.projects.live(), slug=project_slug)
+ subproj = get_object_or_404(Project.objects.public(), slug=child_slug)
+ project.translations.remove(subproj)
+ project_dashboard = reverse('projects_translations', args=[project.slug])
+ return HttpResponseRedirect(project_dashboard)
@@ -15,6 +15,7 @@
<li class="{% block project-edit-active %}{% endblock %}"><a href="{% url projects_edit project.slug %}">{% trans "Settings" %} </a></li>
<li class="{% block project-admins-active %}{% endblock %}"><a href="{% url projects_users project.slug %}">{% trans "Maintainers" %}</a></li>
<li class="{% block project-versions-active %}{% endblock %}"><a href="{% url projects_versions project.slug %}" rel="nofollow,noindex">{% trans "Versions" %}</a></li>
+ <li class="{% block project-translations-active %}{% endblock %}"><a href="{% url projects_translations project.slug %}">{% trans "Translations" %}</a></li>
<li class="{% block project-subprojects-active %}{% endblock %}"><a href="{% url projects_subprojects project.slug %}">{% trans "Subprojects" %}</a></li>
<li class="{% block project-notifications-active %}{% endblock %}"><a href="{% url projects_notifications project.slug %}">{% trans "Notifications" %}</a></li>
</ul>
Oops, something went wrong.

0 comments on commit 25a6101

Please sign in to comment.