Repository: translate/pootle

Issue:
Add some way to map templates before they are loaded
# Steps to reproduce:

- create new project, but call your templates file something other than `templates` like `template.pot` or `other.pot`

# Results (Expected/Actual):

- you want to be able to map templates, but cant as the ui doesnt allow you to edit until templates are loaded

# Environment (i.e. 'pootle --version', DB, OS, Browser):

2.9+


Discussion:

Resolving patch:
diff --git a/pootle/apps/pootle_app/forms.py b/pootle/apps/pootle_app/forms.py
--- a/pootle/apps/pootle_app/forms.py
+++ b/pootle/apps/pootle_app/forms.py
@@ -57,6 +57,7 @@ class ProjectForm(forms.ModelForm):
     fs_plugin = forms.ChoiceField(choices=[], required=True)
     fs_url = forms.CharField(required=True)
     fs_mapping = forms.CharField(required=True)
+    template_name = forms.CharField(required=False)
 
     class Meta(object):
         model = Project
@@ -75,6 +76,8 @@ def __init__(self, *args, **kwargs):
         self.fields["filetypes"].initial = [
             self.fields["filetypes"].queryset.get(name="po")]
         self.fields["fs_plugin"].choices = [(x, x) for x in fs_plugins.gather()]
+        self.fields["template_name"].initial = (
+            self.instance.lang_mapper.get_upstream_code("templates"))
 
     def clean_filetypes(self):
         value = self.cleaned_data.get('filetypes', [])
@@ -97,6 +100,9 @@ def clean_fullname(self):
     def clean_code(self):
         return self.cleaned_data['code'].strip()
 
+    def clean_template_name(self):
+        return self.cleaned_data['template_name'].strip()
+
     def clean_fs_mapping(self):
         fs_mapping = self.cleaned_data["fs_mapping"].strip()
         bad = (
@@ -131,6 +137,17 @@ def save(self, commit=True):
         project.config["pootle_fs.fs_url"] = self.cleaned_data["fs_url"]
         project.config["pootle_fs.translation_mappings"] = dict(
             default=self.cleaned_data["fs_mapping"])
+        lang_mapping = dict(
+            (v, k) for k, v
+            in project.config.get("pootle.core.lang_mapping", {}).iteritems())
+        if self.cleaned_data["template_name"] in ["templates", ""]:
+            if "templates" in lang_mapping:
+                del lang_mapping["templates"]
+        else:
+            lang_mapping["templates"] = self.cleaned_data["template_name"]
+        project.config["pootle.core.lang_mapping"] = dict(
+            (v, k) for k, v
+            in lang_mapping.iteritems())
         return project
 
 
diff --git a/pootle/apps/pootle_app/views/admin/projects.py b/pootle/apps/pootle_app/views/admin/projects.py
--- a/pootle/apps/pootle_app/views/admin/projects.py
+++ b/pootle/apps/pootle_app/views/admin/projects.py
@@ -81,3 +81,5 @@ def serialize_config(self, info, item):
                 info[k] = mapping.get("default")
             else:
                 info[k] = config.get(v)
+        info["template_name"] = (
+            item.lang_mapper.get_upstream_code("templates"))
diff --git a/pootle/apps/pootle_project/views.py b/pootle/apps/pootle_project/views.py
--- a/pootle/apps/pootle_project/views.py
+++ b/pootle/apps/pootle_project/views.py
@@ -6,6 +6,8 @@
 # or later license. See the LICENSE file for a copy of the license and the
 # AUTHORS file for copyright and authorship information.
 
+import posixpath
+
 from django.contrib import messages
 from django.forms.models import modelformset_factory
 from django.http import Http404
@@ -257,6 +259,31 @@ def get_context_data(self, **kwargs_):
             self.process_formset()
 
         formset = self.get_formset()
+        template_path = ""
+        layout_style = None
+        if not self.formset_extra:
+            layout_style = "nongnu"
+            mapping = self.object.config[
+                "pootle_fs.translation_mappings"]["default"]
+            gnustyle = (
+                "/" not in mapping[
+                    mapping.rfind("<language_code>") + 15:])
+            template_path = self.object.lang_mapper.get_upstream_code("templates")
+            if gnustyle:
+                layout_style = "gnu"
+                mapping_root, __ = posixpath.splitext(posixpath.basename(mapping))
+                template_path = mapping_root.replace(
+                    "<language_code>", template_path)
+                template_extensions = self.object.filetypes.values_list(
+                    "template_extension__name", flat=True)
+                template_path = ", ".join(
+                    ('"%(template_name)s.%(extension)s"'
+                     % dict(
+                         template_name=template_path,
+                         extension=ext))
+                    for ext in template_extensions)
+            else:
+                template_path = '"%s"' % template_path
         return {
             'page': 'admin-languages',
             'browse_url': (
@@ -274,6 +301,8 @@ def get_context_data(self, **kwargs_):
             'formset': formset,
             'objects': self.page,
             'error_msg': self.msg,
+            'template_path': template_path,
+            'layout_style': layout_style,
             'can_add': self.formset_extra}
 
     def get_formset(self, post=None):


Test patch:
diff --git a/tests/forms/project.py b/tests/forms/project.py
--- a/tests/forms/project.py
+++ b/tests/forms/project.py
@@ -199,3 +199,31 @@ def test_form_project_fs_mapping(format_registry):
     form = ProjectForm(form_data)
     assert not form.is_valid()
     assert 'fs_mapping' in form.errors
+
+
+@pytest.mark.django_db
+def test_form_project_template_name(format_registry):
+    form_data = {
+        'code': 'foo0',
+        'checkstyle': PROJECT_CHECKERS.keys()[0],
+        'fullname': 'Foo',
+        'fs_plugin': "localfs",
+        'fs_url': "{POOTLE_TRANSLATION_DIRECTORY}foo0",
+        'fs_mapping': "/<language_code>.<ext>",
+        'filetypes': [format_registry["po"]["pk"]],
+        'source_language': 1}
+    form = ProjectForm(form_data)
+    assert form.is_valid()
+    assert form.cleaned_data["template_name"] == ""
+    project = form.save()
+    assert project.lang_mapper.get_upstream_code("templates") == "templates"
+    form_data["template_name"] = "foo"
+    form = ProjectForm(instance=project, data=form_data)
+    form.save()
+    del project.__dict__["lang_mapper"]
+    assert project.lang_mapper.get_upstream_code("templates") == "foo"
+    form_data["template_name"] = ""
+    form = ProjectForm(instance=project, data=form_data)
+    form.save()
+    del project.__dict__["lang_mapper"]
+    assert project.lang_mapper.get_upstream_code("templates") == "templates"
diff --git a/tests/views/admin.py b/tests/views/admin.py
--- a/tests/views/admin.py
+++ b/tests/views/admin.py
@@ -21,6 +21,7 @@
 from pootle.core.views.admin import PootleAdminFormView, PootleAdminView
 from pootle_app.models import PermissionSet
 from pootle_app.views.admin.util import form_set_as_table
+from pootle_format.models import Format
 from pootle_fs.delegate import fs_plugins
 from pootle_fs.presets import FS_PRESETS
 from pootle_language.models import Language
@@ -311,3 +312,33 @@ def test_admin_view_projects(client, request_users, english):
                 'source_language': english.id}}}
     for k, v in expected.items():
         assert response.context_data[k] == v
+
+
+@pytest.mark.django_db
+def test_admin_view_project_templates(client, admin, project0, templates):
+    client.login(
+        username=admin.username,
+        password=TEST_USERS["admin"]["password"])
+    response = _admin_view_get(client, project0)
+    assert response.context["can_add"] is True
+    assert not response.context["template_path"]
+    assert not response.context["layout_style"]
+    project0.translationproject_set.get(
+        language__code="templates").delete()
+    response = _admin_view_get(client, project0)
+    assert response.context["can_add"] is False
+    assert response.context["layout_style"] == "nongnu"
+    assert response.context["template_path"] == '"templates"'
+
+    project0.config["pootle_fs.translation_mappings"] = dict(
+        default="/<language_code>.<ext>")
+    response = _admin_view_get(client, project0)
+    assert response.context["layout_style"] == "gnu"
+    assert response.context["template_path"] == '"templates.pot"'
+
+    project0.filetypes.add(Format.objects.get(name="xliff"))
+    response = _admin_view_get(client, project0)
+    assert response.context["layout_style"] == "gnu"
+    assert (
+        response.context["template_path"]
+        == u'"templates.pot", "templates.xliff"')