changeset 198:ac552caafd4b

More i18n setup.
author Sylvain Beucler <beuc@beuc.net>
date Wed, 28 Jul 2010 23:39:57 +0200
parents 6c2426e44082
children 84d9c715d8ec
files TODO doc/DJANGO_I18N locale/README savane/svmain/urls.py templates/base.html templates/svmain/group_detail.html templates/svmain/group_gpgkeyring.html templates/svmain/group_memberlist.html templates/svmain/pagination.inc.html
diffstat 9 files changed, 96 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/TODO
+++ b/TODO
@@ -112,11 +112,7 @@
 
 [ ] Translations
 
-    [ ] Design the translation build system: we need to parse the web
-        templates (./manage.py makemessages), and see how to install
-        .po files for Django (in particular Django uses one .po file
-        per app, and Savane is split in multiple apps, so maybe we
-        need to split the existing translations).
+    [ ] Design the translation build system; cf. doc/DJANGO_I18N.
 
     [ ] Translate new strings and generally update existing
         translations.
new file mode 100644
--- /dev/null
+++ b/doc/DJANGO_I18N
@@ -0,0 +1,61 @@
+Translations
+============
+
+You create them with either:
+
+- a monolithic translation catalog
+
+  cd framework/
+  mkdir locale/  # or conf/locale/
+  django-admin makemessages -l fr
+  django-admin compilemessages -l fr
+
+- per-app translation catalogs:
+
+  cd framework/savane/svmain/
+  mkdir locale/
+  django-admin makemessages -l fr
+  django-admin compilemessages -l fr
+
+- in both cases, to update:
+
+  cd ...
+  django-admin makemessages -a
+
+Monolithic translations are not suited for deploying reusable apps
+(because they are installed in the projects rather than in the
+applications).
+
+Per-app translation catalog means splitting the Savane 3 catalog.
+It's not hard to do: just duplicate the current catalog in all
+applications, and update the catalogs (all unused strings will be
+commented out).
+
+Per-app translation catalogs also means moving the templates in the
+application directory, otherwise they won't be parsed.  For example:
+
+  framework/savane/svmain/templates/svmain/group_detail.html
+
+Also this means placing top-level templates in an application, so that
+its strings get translated too (e.g. move templates/base.html to
+framework/savane/svmain/templates/base.html).
+
+
+Given that "reusable apps" in Django is mostly utopia as of 2010, and
+given the constraints of per-app translation catalogs, let's use a
+monolithic translation catalog for now.
+
+
+Notes:
+
+- Django needs to be restarted to take new translations into account
+  (they are cached).
+
+- Template {% blocktrans %} blocks takes newlines into account, so
+  better write them on a signe line, even if it's very long.
+
+- {% blocktrans %} uses mappings ('%(variable)s' instead of '%s'),
+  which is not compatible with Savane 3's .po strings.  Consequently
+  we'll get a lot fuzzy strings that translators will need to review.
+  Thus let's not worry so much about introducing fuzzy strings:
+  typically let's not keep All Firstcap Titles that cripple Savane 3.
new file mode 100644
--- /dev/null
+++ b/locale/README
@@ -0,0 +1,8 @@
+When this directory exists, you can create a top-level translation
+file:
+
+  django-admin makemessages -l fr
+  django-admin compilemessages
+  ...
+
+Cf. doc/DJANGO_I18N for further information.
--- a/savane/svmain/urls.py
+++ b/savane/svmain/urls.py
@@ -87,12 +87,12 @@
   url(r'^p/(?P<slug>[-\w]+)/memberlist/$', object_detail,
       { 'queryset' : auth_models.Group.objects.all(),
         'slug_field' : 'name',
-        'extra_context' : { 'title' : 'Project Memberlist' },
+        'extra_context' : { 'title' : 'Project memberlist' },
         'template_name' : 'svmain/group_memberlist.html',
         'template_object_name' : 'group', },
       name='savane.svmain.group_memberlist'),
   url(r'^p/(?P<slug>[-\w]+)/gpgkeyring/$', views.group_gpgkeyring,
-      { 'extra_context' : { 'title' : 'Project Members GPG Keyring' }, },
+      { 'extra_context' : { 'title' : 'Project members GPG keyring' }, },
       name='savane.svmain.group_gpgkeyring'),
   url(r'^p/(?P<slug>[-\w]+)/gpgkeyring/download/$', views.group_gpgkeyring_download,
       name='savane.svmain.group_gpgkeyring_download'),
--- a/templates/base.html
+++ b/templates/base.html
@@ -14,24 +14,24 @@
     <div class="realbody">
       <ul class="menu">
         <!-- sitemenu -->
-        <li><a href="/"><img src="{{STATIC_MEDIA_URL}}savane/images/floating.png" alt="Back to homepage" border="0" width="118" height="100" /></a></li>
+        <li><a href="/"><img src="{{STATIC_MEDIA_URL}}savane/images/floating.png" alt="{% trans "Back to homepage" %}" border="0" width="118" height="100" /></a></li>
         {% if user.is_authenticated %}
-          <li class="menutitle">Connected as {{ user.username}}</li>
-          <li class="menuitem"><a href="{% url savane.my.index %}">My account</a></li>
-          <li class="menuitem"><a href="{% url django.contrib.auth.views.logout %}">Logout</a></li>
+          <li class="menutitle">{% blocktrans with user.username as username %}Connected as {{username}}{% endblocktrans %}</li>
+          <li class="menuitem"><a href="{% url savane.my.index %}">{% trans "My account" %}</a></li>
+          <li class="menuitem"><a href="{% url django.contrib.auth.views.logout %}">{% trans "Logout" %}</a></li>
         {% else %}
-          <li class="menutitle">Login status</li>
-          <li class="menuitem"><span class="error">Not connected</span></li>
-          <li class="menuitem"><a href="{% url django.contrib.auth.views.login %}">Login</a></li>
-          <li class="menuitem"><a href="{% url registration_register %}">New user</a></li>
+          <li class="menutitle">{% trans "Login status" %}</li>
+          <li class="menuitem"><span class="error">{% trans "Not connected" %}</span></li>
+          <li class="menuitem"><a href="{% url django.contrib.auth.views.login %}">{% trans "Login" %}</a></li>
+          <li class="menuitem"><a href="{% url registration_register %}">{% trans "New user" %}</a></li>
         {% endif %}
 
-	<li class="menutitle">Search</li>
-        <li class="menuitem"><a href="{% url savane.svmain.user_list %}">Users</a></li>
-        <li class="menuitem"><a href="{% url savane.svmain.group_list %}">Projects</a></li>
+	<li class="menutitle">{% trans "Search" %}</li>
+        <li class="menuitem"><a href="{% url savane.svmain.user_list %}">{% trans "Users" %}</a></li>
+        <li class="menuitem"><a href="{% url savane.svmain.group_list %}">{% trans "Projects" %}</a></li>
 
-	<li class="menutitle">Site help</li>
-        <li class="menuitem"><a href="{% url contact %}">Contact us</a></li>
+	<li class="menutitle">{% trans "Site help" %}</li>
+        <li class="menuitem"><a href="{% url contact %}">{% trans "Contact us" %}</a></li>
         <!-- /sitemenu -->
       </ul>
 
--- a/templates/svmain/group_detail.html
+++ b/templates/svmain/group_detail.html
@@ -10,9 +10,9 @@
 
 <div class="indexright">
   <div class="box">
-    <div class="boxtitle">{% trans "Membership Info" %}</div>
+    <div class="boxtitle">{% trans "Membership info" %}</div>
     {% if group.svgroupinfo.get_admin_memberships %}
-    <div class="boxitem smaller">{% trans "Project Admins:" %}</div>
+    <div class="boxitem smaller">{% trans "Project admins:" %}</div>
     {% for membership in group.svgroupinfo.get_admin_memberships %}
     <div class="{% cycle 'boxitemalt' 'boxitem' %} smaller">&nbsp;
 	- <a href="{% url savane.svmain.user_detail membership.user.username %}">{{ membership.user.svuserinfo.get_full_name_display }}</a></div>
@@ -21,14 +21,14 @@
     <div class="boxitem smaller">{% trans "No members!" %}</div>
     {% endif %}
     <div class="boxitem smaller">{% blocktrans count group.user_set.count as count %}{{count}} active member{% plural %}{{count}} active members{% endblocktrans %}</div>
-    <div class="boxitemalt smaller">[<a href="memberlist/">{% trans "View Members" %}</a>]</div>
+    <div class="boxitemalt smaller">[<a href="{% url savane.svmain.group_memberlist group.name %}">{% trans "View members" %}</a>]</div>
   </div>
   <div class="box">
     <div class="boxtitle">{% trans "Group identification" %}</div>
     <div class="boxitem smaller">{% trans "Id:" %} <strong>#{{group.pk}}</strong></div>
-    <div class="boxitemalt smaller">{% trans "System Name:" %} <strong>{{group.name}}</strong></div>
+    <div class="boxitemalt smaller">{% trans "System name:" %} <strong>{{group.name}}</strong></div>
     <div class="boxitem smaller">{% trans "Name:" %} <strong>{{group.svgroupinfo.full_name}}</strong></div>
-    <div class="boxitemalt smaller">{% trans "Group Type:" %} <strong>{{group.svgroupinfo.type.name}}</strong></div>
+    <div class="boxitemalt smaller">{% trans "Group type:" %} <strong>{{group.svgroupinfo.type.name}}</strong></div>
   </div>
 </div>
 
@@ -36,9 +36,9 @@
 <p>{{group.svgroupinfo.type.description}}</p>
 <p>{{group.svgroupinfo.long_description}}</p>
 <p>
-{% trans "Registration Date" %}: {{group.svgroupinfo.register_time}}<br />
+{% trans "Registration date" %}: {{group.svgroupinfo.register_time}}<br />
 {% trans "License" %}: <a href="{{group.svgroupinfo.license.get_absolute_url}}">{{group.svgroupinfo.license.name}}</a><br />
-{% trans "Development Status" %}: {{group.svgroupinfo.devel_status}}<br />
+{% trans "Development status" %}: {{group.svgroupinfo.devel_status}}<br />
 </p>
 </div>
 
--- a/templates/svmain/group_gpgkeyring.html
+++ b/templates/svmain/group_gpgkeyring.html
@@ -20,9 +20,7 @@
   <p>{{ gpgkeyring }}</p>
   {% endcomment %}
   {% url savane.svmain.group_gpgkeyring_download group.name as url_download %}
-{% blocktrans with '<a href="'|add:url_download|add:'">'|safe as begin_link and '</a>' as end_link and '<em>gpg --import &lt;file&gt;</em>' as command %}
-You can {{begin_link}}download the keyring{{end_link}} and import it with the command {{command}}
-{% endblocktrans %}
+  {% blocktrans with '<a href="'|add:url_download|add:'">'|safe as begin_link and '</a>' as end_link and '<em>gpg --import &lt;file&gt;</em>' as command %}You can {{begin_link}}download the keyring{{end_link}} and import it with the command {{command}}{% endblocktrans %}
   </p>
 {% else %}
   {% trans "They GPG Keyring of the project is empty, no keys were registered" %}
--- a/templates/svmain/group_memberlist.html
+++ b/templates/svmain/group_memberlist.html
@@ -36,9 +36,7 @@
 
 <p>
 {% url savane.svmain.group_gpgkeyring group.name as url_gpgkeyring %}
-{% blocktrans with '<a href="'|add:url_gpgkeyring|add:'">'|safe as begin_link and '</a>' as end_link %}
-You may also be interested in the {{begin_link}}GPG Keyring of this project{{end_link}}
-{% endblocktrans %}
+{% blocktrans with '<a href="'|add:url_gpgkeyring|add:'">'|safe as begin_link and '</a>' as end_link %}You may also be interested in the {{begin_link}}GPG Keyring of this project{{end_link}}{% endblocktrans %}
 </p>
 
 {% endblock %}
--- a/templates/svmain/pagination.inc.html
+++ b/templates/svmain/pagination.inc.html
@@ -26,16 +26,10 @@
 
         <span class="current">
 	    -
-            {% blocktrans with page_obj.number as number and paginator.num_pages as num_pages and paginator.count as count %}
-            Page {{ page_obj.number }} on {{ num_pages }} ({{ count }})
-	    {% endblocktrans %}
+            {% blocktrans with page_obj.number as number and paginator.num_pages as num_pages and paginator.count as count %}Page {{ page_obj.number }} on {{ num_pages }} ({{ count }}){% endblocktrans %}
         </span>
       {% else %}
-        {% blocktrans count paginator.count as count %}
-	{{count}} element
-	{% plural %}
-	{{count}} elements
-	{% endblocktrans %}
+        {% blocktrans count paginator.count as count %}{{count}} element{% plural %}{{count}} elements{% endblocktrans %}
       {% endif %}
     </span>
 </div>