diff --exclude=.svn -Naur trac-0.10.4/AUTHORS trac-0.10.4-PKG/AUTHORS --- trac-0.10.4/AUTHORS 2007-04-20 15:41:52.000000000 +0200 +++ trac-0.10.4-PKG/AUTHORS 2007-08-24 09:32:19.000000000 +0200 @@ -1,4 +1,4 @@ - * Jonas Borgström + * Jonas Borgström * Daniel Lundin * Rocky Burt * Christopher Lenz @@ -6,7 +6,7 @@ * Mark Rowe * Matthew Good * Christian Boos - * Emmanual Blot + * Emmanuel Blot * Alec Thomas See also THANKS for people who have contributed to the project. diff --exclude=.svn -Naur trac-0.10.4/cgi-bin/trac.cgi trac-0.10.4-PKG/cgi-bin/trac.cgi --- trac-0.10.4/cgi-bin/trac.cgi 2007-04-20 15:41:52.000000000 +0200 +++ trac-0.10.4-PKG/cgi-bin/trac.cgi 2007-08-24 09:32:19.000000000 +0200 @@ -28,10 +28,10 @@ traceback.print_exc(file=sys.stderr) print 'Status: 500 Internal Server Error' - print 'Content-Type: text/plain' + print 'Content-Type: text/plain;charset=utf-8\r\n\r\n' print - print 'Oops...' + print 'Aie...' print - print 'Trac detected an internal error:', e + print 'Trac a détecté une erreur interne:', e print traceback.print_exc(file=sys.stdout) diff --exclude=.svn -Naur trac-0.10.4/cgi-bin/trac.fcgi trac-0.10.4-PKG/cgi-bin/trac.fcgi --- trac-0.10.4/cgi-bin/trac.fcgi 2007-04-20 15:41:52.000000000 +0200 +++ trac-0.10.4-PKG/cgi-bin/trac.fcgi 2007-08-24 09:32:19.000000000 +0200 @@ -21,10 +21,10 @@ except SystemExit: raise except Exception, e: - print 'Content-Type: text/plain\r\n\r\n', - print 'Oops...' + print 'Content-Type: text/plain;charset=utf-8\r\n\r\n', + print 'Aie...' print - print 'Trac detected an internal error:' + print 'Trac a détecté une erreur interne :' print print e print diff --exclude=.svn -Naur trac-0.10.4/htdocs/css/trac.css trac-0.10.4-PKG/htdocs/css/trac.css --- trac-0.10.4/htdocs/css/trac.css 2007-04-20 15:41:41.000000000 +0200 +++ trac-0.10.4-PKG/htdocs/css/trac.css 2007-08-27 16:41:34.000000000 +0200 @@ -63,7 +63,7 @@ background: url(../extlink.gif) left center no-repeat; padding-left: 16px; } - * html a.ext-link .icon { display: inline-block; } + * html a.ext-link .icon { display: inline; } } /* Forms */ @@ -99,7 +99,7 @@ .buttons { margin: .5em .5em .5em 0 } .buttons form, .buttons form div { display: inline } .buttons input { margin: 1em .5em .1em 0 } -.inlinebuttons input { +.inlinebuttons input { font-size: 70%; border-width: 1px; border-style: dotted; @@ -316,12 +316,12 @@ overflow: auto; } -blockquote.citation { +blockquote.citation { margin: -0.6em 0; - border-style: solid; - border-width: 0 0 0 2px; + border-style: solid; + border-width: 0 0 0 2px; padding-left: .5em; - border-color: #b44; + border-color: #b44; } .citation blockquote.citation { border-color: #4b4; } .citation .citation blockquote.citation { border-color: #44b; } diff --exclude=.svn -Naur trac-0.10.4/htdocs/js/query.js trac-0.10.4-PKG/htdocs/js/query.js --- trac-0.10.4/htdocs/js/query.js 2007-04-20 15:41:42.000000000 +0200 +++ trac-0.10.4-PKG/htdocs/js/query.js 2007-08-21 11:27:21.000000000 +0200 @@ -106,7 +106,7 @@ if (select.options[select.selectedIndex].disabled) { // Neither IE nor Safari supported disabled options at the time this was // written, so alert the user - alert("A filter already exists for that property"); + alert("Un filtre existe déjà pour cette propriété"); return; } diff --exclude=.svn -Naur trac-0.10.4/htdocs/js/wikitoolbar.js trac-0.10.4-PKG/htdocs/js/wikitoolbar.js --- trac-0.10.4/htdocs/js/wikitoolbar.js 2007-04-20 15:41:42.000000000 +0200 +++ trac-0.10.4-PKG/htdocs/js/wikitoolbar.js 2007-08-24 09:32:19.000000000 +0200 @@ -48,28 +48,28 @@ } } - addButton("strong", "Bold text: '''Example'''", function() { + addButton("strong", "Texte gras: '''Exemple'''", function() { encloseSelection("'''", "'''"); }); - addButton("em", "Italic text: ''Example''", function() { + addButton("em", "Texte italique: ''Exemple''", function() { encloseSelection("''", "''"); }); - addButton("heading", "Heading: == Example ==", function() { + addButton("heading", "En-tête: == Exemple ==", function() { encloseSelection("\n== ", " ==\n", "Heading"); }); - addButton("link", "Link: [http://www.example.com/ Example]", function() { + addButton("link", "Lien: [http://www.exemple.com/ Exemple]", function() { encloseSelection("[", "]"); }); - addButton("code", "Code block: {{{ example }}}", function() { + addButton("code", "Bloc de code: {{{ exemple }}}", function() { encloseSelection("\n{{{\n", "\n}}}\n"); }); - addButton("hr", "Horizontal rule: ----", function() { + addButton("hr", "Séparateur horizontal: ----", function() { encloseSelection("\n----\n", ""); }); - addButton("np", "New paragraph", function() { + addButton("np", "Nouveau paragraphe", function() { encloseSelection("\n\n", ""); }); - addButton("br", "Line break: [[BR]]", function() { + addButton("br", "Retour à la ligne: [[BR]]", function() { encloseSelection("[[BR]]\n", ""); }); diff --exclude=.svn -Naur trac-0.10.4/scripts/trac-admin trac-0.10.4-PKG/scripts/trac-admin --- trac-0.10.4/scripts/trac-admin 2007-04-20 15:41:44.000000000 +0200 +++ trac-0.10.4-PKG/scripts/trac-admin 2007-08-21 11:32:53.000000000 +0200 @@ -1,10 +1,10 @@ #!/usr/bin/env python -# -*- coding: iso8859-1 -*- -__author__ = 'Daniel Lundin , Jonas Borgström ' +# -*- coding: utf-8 -*- +__author__ = 'Daniel Lundin , Jonas Borgström ' __copyright__ = 'Copyright (c) 2005 Edgewall Software' __license__ = """ Copyright (C) 2003, 2004, 2005 Edgewall Software - Copyright (C) 2003, 2004 Jonas Borgström + Copyright (C) 2003, 2004 Jonas Borgström Copyright (C) 2003, 2004 Daniel Lundin All rights reserved. diff --exclude=.svn -Naur trac-0.10.4/scripts/tracd trac-0.10.4-PKG/scripts/tracd --- trac-0.10.4/scripts/tracd 2007-04-20 15:41:44.000000000 +0200 +++ trac-0.10.4-PKG/scripts/tracd 2007-08-21 11:33:27.000000000 +0200 @@ -1,8 +1,8 @@ #!/usr/bin/env python -# -*- coding: iso8859-1 -*- +# -*- coding: utf-8 -*- # # Copyright (C) 2003-2006 Edgewall Software -# Copyright (C) 2003-2005 Jonas Borgström +# Copyright (C) 2003-2005 Jonas Borgström # All rights reserved. # # This software is licensed as described in the file COPYING, which @@ -13,7 +13,7 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://trac.edgewall.org/log/. # -# Author: Jonas Borgström +# Author: Jonas Borgström if __name__ == '__main__': from trac.web.standalone import main diff --exclude=.svn -Naur trac-0.10.4/templates/about.cs trac-0.10.4-PKG/templates/about.cs --- trac-0.10.4/templates/about.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/about.cs 2007-08-24 09:32:19.000000000 +0200 @@ -1,14 +1,14 @@ @@ -17,7 +17,7 @@

Configuration

- Nom
SectionNameValue
Valeur
- See TracIni for information about - the configuration. + Voir TracIni pour obtenir des + informations sur la configuration.
-

Plugins

+

Extensions

@@ -50,7 +50,7 @@ - Extension points: @@ -75,20 +75,20 @@ Trac: Integrated SCM & Project Management -

About Trac

-

Trac is a web-based software project management and bug/issue tracking - system emphasizing ease of use and low ceremony. It provides an integrated - Wiki, an interface to version control systems, and a number convenient ways - to stay on top of events and changes within a project.

-

Trac is distributed under the modified BSD License. The complete text of - the license can be found - online as well as in - the COPYING file included in the distribution.

+

À propos de Trac

+

Trac est un système de gestion de projet logiciel et de suivi de défauts/bogues via le + Web, qui met l'accent sur la facilité d'utilisation et évite les chichis. + Il propose une interface pour le système de contrôle de source Subversion, un + Wiki intégré, et un nombre intéressant d'option permettant de rester au courant des évènements et + changements d'un projet.

+

Trac est distribué sous une licence BSD modifiée. Le texte entier de la licence peut être consulté + en ligne aussi bien que dans le fichier + COPYING inclus dans cette distribution.

python powered -

Please visit the Trac open source project at +

Merci de consulter le projet open source Trac http://trac.edgewall.org/.

Copyright © 2003-2006 Edgewall Software

diff --exclude=.svn -Naur trac-0.10.4/templates/anydiff.cs trac-0.10.4-PKG/templates/anydiff.cs --- trac-0.10.4/templates/anydiff.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/anydiff.cs 2007-08-24 09:33:31.000000000 +0200 @@ -4,41 +4,42 @@
-

Select Base and Target for Diff:

+

Sélectionnez la base et la cible pour les différences :

- + - +
- +
- +
- +
- Note: See TracChangeset for help on using the arbitrary diff feature. + Remarque : Consultez la page TracChangeset pour plus d'informations + sur l'utilisation de la fonction de différence.
diff --exclude=.svn -Naur trac-0.10.4/templates/attachment.cs trac-0.10.4-PKG/templates/attachment.cs --- trac-0.10.4/templates/attachment.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/attachment.cs 2007-08-24 09:44:59.000000000 +0200 @@ -6,29 +6,29 @@
-

Add Attachment to Joindre un fichier à

- +
- Attachment Info + Info sur le fichier
-
-

+ Remplacer une pièce jointe existante portant le même nom

@@ -36,20 +36,20 @@ - - + +

:

-

Are you sure you want to delete this attachment?
- This is an irreversible operation.

+

Etes-vous sûr de vouloir supprimer ce fichier ?
+ Cette opération est irréversible.

- - + +
@@ -62,7 +62,7 @@ @@ -71,18 +71,18 @@ if:attachment.preview ?> - HTML preview not available, since the file size exceeds - bytes. You may download the file instead. - HTML preview not available. To view the file, - download the file.Prévisualisation HTML impossible, car la taille du fichier + dépasse octets. En revanche, vous + pouvez télécharger le fichier. + + Prévisualisation HTML impossible. Pour voir son contenu, + télécharge le fichier.
- +
diff --exclude=.svn -Naur trac-0.10.4/templates/browser.cs trac-0.10.4-PKG/templates/browser.cs --- trac-0.10.4/templates/browser.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/browser.cs 2007-08-24 09:44:59.000000000 +0200 @@ -4,9 +4,9 @@ @@ -18,7 +18,7 @@
- +
@@ -28,8 +28,8 @@
@@ -38,18 +38,18 @@
File , - (added by , ago) + (ajoûté par , auparavant)
-
- + - + @@ -59,15 +59,15 @@ - @@ -82,18 +82,18 @@ /if ?> -
RevRévLast ChangeDernière modification
- ../
- -
- HTML preview not available, since the file size exceeds - bytes. Try downloading the file instead.HTML preview not available. To view, download the file.Prévisualiation HTML non disponible, car la taille du + fichier excède octets. Essayez plutôt de + télécharger le fichier.Prévisualiation HTML non disponible. Pour voir le + contenu du fichier, téléchargez-le.
- Note: See TracBrowser for help on using the browser. + Remarque : Consulter la page TracBrowser pour plus d'informations sur l'utilisation du Navigateur.
@@ -127,7 +127,7 @@ - +
diff --exclude=.svn -Naur trac-0.10.4/templates/changeset.cs trac-0.10.4-PKG/templates/changeset.cs --- trac-0.10.4/templates/changeset.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/changeset.cs 2007-08-24 09:44:59.000000000 +0200 @@ -7,28 +7,32 @@ @@ -38,29 +42,29 @@
-

Changeset +

Version - for + pour

-

Changeset

Enregistrement -

Changes in +

Modifications dans - + [:]

-

Changes from +

Modification de - at + à r - to + vers - at + à r

" /> - +
- Show - +
- Ignore: + Ignorer:
checked="checked" /> - +
checked="checked" /> - +
checked="checked" /> - +
- +

@@ -124,22 +128,22 @@ set:nprops = len(item.props) ?>
- )" href=""> - (root)">(racine)() - ( from " title="Montrer le fichier original (rév. )">) - (view diffs)" title="Voir les différences">voir diffs) #0 ?> - (" title="Voir les différences"> #0 ?> diff #1 ?>s, ) (previous)précédent)
-
Timestamp:
+
Date:
- (less than one hour ago)
-
Author:
+ (moins d'une heure auparavant) +
Auteur:
:
@@ -168,24 +172,24 @@ /if ?>
#0 ?> - Files: - (No files)
@@ -194,47 +198,47 @@
-

Legend:

+

Légende:

-
Unmodified
-
Added
-
Removed
-
Modified
-
Copied
-
Moved
+
Non modifié
+
Ajouté
+
Supprimé
+
Modifié
+
Copié
+
Déplacé
- Revision , - (checked in by , ago) + Révision , + (déposée par , auparavant)
    -
  • Property set to Propriété définie à
" summary="Différences" cellspacing="0"> - -

-

Oops…

+

Aïe…

- Trac detected an internal error: + Trac a détecté une erreur interne :
-

If you think this really should work and you can reproduce it, you should - consider reporting this problem to the Trac team.

-

Go to and create a new ticket where you describe - the problem, how to reproduce it. Don't forget to include the Python - traceback found below.

- +

Si vous pensez que cette action aurait du fonctionner et si vous pouvez + reproduire le problème, vous devriez envisager de le rapporter à + l'équipe de Trac.

+

Rendez vous sur et créez un nouveau ticket où vous décrirez le + problème, et comment le reproduire. N'oubliez pas d'inclure la pile d'appel + Python affichée ci-dessous. +

TracGuide - — The Trac User and Administration Guide + — Le Guide de l'utilisateur et de l'administrateur de Trac

-

Python Traceback

+

Pile d'appel Python

diff --exclude=.svn -Naur trac-0.10.4/templates/footer.cs trac-0.10.4-PKG/templates/footer.cs --- trac-0.10.4/templates/footer.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/footer.cs 2007-08-24 09:46:29.000000000 +0200 @@ -1,6 +1,6 @@ -
Revision " title="Voir ancienne rév. de ">Révision Revision " title="Voir nouvelle rév. de ">Révision
">r">r  
- - + + - - + + @" checked="checked" /> @@ -149,8 +149,8 @@
RevChgsetRév.Version DateAuthorLog MessageAuteurDescription
- copied from : + copié depuis :
- + () @ + title="Consultez la révision ">@ [] + title="Voir la version []">[]
#10 ?> -
+
  • Younger Revisions
  • ">Révisions postérieures
  • Older Revisions
  • ">Révisions antérieures →
    - Note: See TracRevisionLog for help on using the revision log. + Remarque : Consultez la page TracRevisionLog pour plus d'informations sur l'utilisation de l'historique des révisions.
    diff --exclude=.svn -Naur trac-0.10.4/templates/log_rss.cs trac-0.10.4-PKG/templates/log_rss.cs --- trac-0.10.4/templates/log_rss.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/log_rss.cs 2007-08-24 09:51:59.000000000 +0200 @@ -3,13 +3,13 @@ - <?cs var:project.name_encoded ?>: Revisions of <?cs var:log.path ?>: Révisions de - Revisions of <?cs var:log.path ?>Révisions de - Trac Log - Revisions of - en-us + Journal de Trac - Révisions de + fr-fr Trac v @@ -25,12 +25,12 @@ if:change.author ?> - Revision <?cs var:item.rev ?>: <?cs var:change.shortlog ?> + Révision <?cs var:item.rev ?>: <?cs var:change.shortlog ?> - Log + Historique diff --exclude=.svn -Naur trac-0.10.4/templates/macros.cs trac-0.10.4-PKG/templates/macros.cs --- trac-0.10.4/templates/macros.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/macros.cs 2007-08-24 09:51:59.000000000 +0200 @@ -2,8 +2,8 @@ class="first" title="Go to root directory" class="first" title="Retourner au répertoire racine" title="View " title="Voir " href="">/
    -
    - +
    @@ -101,19 +102,19 @@
    -

    Are you sure you want to delete this milestone?

    +

    Voulez-vous vraiment détruire ce jalon ?

    - +
    - - + +
    @@ -121,15 +122,15 @@
    @@ -228,7 +238,9 @@ if:milestone.id_param ?> - +
    - Note: See TracRoadmap for help on using the roadmap. + Note : Voir TracRoadmap pour une aide sur l'utilisation + des Jalons.
    diff --exclude=.svn -Naur trac-0.10.4/templates/newticket.cs trac-0.10.4-PKG/templates/newticket.cs --- trac-0.10.4/templates/newticket.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/newticket.cs 2007-08-24 10:12:34.000000000 +0200 @@ -7,19 +7,19 @@
    -

    Create New Ticket

    +

    Créer un nouveau ticket

    -
    +

    -
    +
    -
    +
    - Description Preview + Aperçu de la description
    - Ticket Properties + Propriétés du ticket colspan="3">" name=""> selected="selected"> checked="checked" /> - I have files to attach to this ticket + Joindre des fichiers à ce ticket

    -   - +   +
    -
    - Note: See TracTickets for help on using tickets. +
    + Note : Voir TracTickets pour plus d'informations sur l'utilisation des tickets. +
    diff --exclude=.svn -Naur trac-0.10.4/templates/query.cs trac-0.10.4-PKG/templates/query.cs --- trac-0.10.4/templates/query.cs 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/templates/query.cs 2007-08-24 10:12:34.000000000 +0200 @@ -4,13 +4,13 @@ (No matches)Pas de résultat 1 ?>s)
    @@ -18,7 +18,7 @@
    - Filters + Filtres checked="checked" -
    +
    - - + - +
    - selected="selected"> selected="selected">
    _" name="" value="" /> - _">none checked="checked" /> - + checked="checked" /> - _off">non
    -   +   @@ -124,21 +129,22 @@

    - + checked="checked" /> - +

    - Note: See WikiFormatting and TracWiki for help on editing wiki content. + Note: Voir l'aide sur le format Wiki et le Wiki de Trac pour l'édition du contenu.
    - Change information + Informations sur les modifications
    -
    -

    @@ -310,19 +310,19 @@
    + Page non modifiable
    -   -   +   +   -   -   +   +   - +
    @@ -332,7 +332,7 @@ @@ -342,13 +342,13 @@
    -

    Attachments

    +

    Pièces jointes

    • () -, added by on ajouté par le .
    @@ -359,13 +359,13 @@ if:trac.acl.WIKI_MODIFY ?>
    - +
    - +
    - - + diff --exclude=.svn -Naur trac-0.10.4/THANKS trac-0.10.4-PKG/THANKS --- trac-0.10.4/THANKS 2007-04-20 15:41:52.000000000 +0200 +++ trac-0.10.4-PKG/THANKS 2007-08-24 12:28:31.000000000 +0200 @@ -50,6 +50,7 @@ * Noah Slater nslater@gmail.com * Bill Soudan bill@soudan.net * Ludvig Strigeus + * Nicolas Ternisien nicolas.ternisien@gmail.com * Alec Thomas alec@swapoff.org * Jani Tiainen redetin@luukku.com * Zilvinas Valinskas zilvinas@gemtek.lt diff --exclude=.svn -Naur trac-0.10.4/trac/About.py trac-0.10.4-PKG/trac/About.py --- trac-0.10.4/trac/About.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/About.py 2007-08-24 10:33:19.000000000 +0200 @@ -38,7 +38,7 @@ def get_navigation_items(self, req): yield ('metanav', 'about', - html.a('About Trac', href=req.href.about())) + html.a(u'À propos de Trac', href=req.href.about())) # IPermissionRequestor methods @@ -56,7 +56,7 @@ def process_request(self, req): page = req.args.get('page', 'default') - req.hdf['title'] = 'About Trac' + req.hdf['title'] = u'À propos de Trac' if req.perm.has_permission('CONFIG_VIEW'): req.hdf['about.config_href'] = req.href.about('config') req.hdf['about.plugins_href'] = req.href.about('plugins') @@ -73,7 +73,7 @@ def _render_config(self, req): req.perm.assert_permission('CONFIG_VIEW') req.hdf['about.page'] = 'config' - + # Export the config table to hdf sections = [] for section in self.config.sections(): @@ -83,7 +83,7 @@ default = default_options and default_options.get(name) or '' options.append({ 'name': name, 'value': value, - 'valueclass': (unicode(value) == unicode(default) + 'valueclass': (unicode(value) == unicode(default) and 'defaultvalue' or 'value')}) options.sort(lambda x,y: cmp(x['name'], y['name'])) sections.append({'name': section, 'options': options}) diff --exclude=.svn -Naur trac-0.10.4/trac/attachment.py trac-0.10.4-PKG/trac/attachment.py --- trac-0.10.4/trac/attachment.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/attachment.py 2007-08-24 10:38:54.000000000 +0200 @@ -54,7 +54,7 @@ class IAttachmentManipulator(Interface): """Extension point interface for components that need to manipulate attachments. - + Unlike change listeners, a manipulator can reject changes being committed to the database.""" def prepare_attachment(req, attachment, fields): @@ -64,7 +64,7 @@ def validate_attachment(req, attachment): """Validate an attachment after upload but before being stored in Trac environment. - + Must return a list of `(field, message)` tuples, one for each problem detected. `field` can be any of `description`, `username`, `filename`, `content`, or `None` to indicate an overall problem with the @@ -100,8 +100,8 @@ cursor.close() if not row: self.filename = filename - raise TracError('Attachment %s does not exist.' % (self.title), - 'Invalid Attachment') + raise TracError(u'La pièce jointe %s n\'existe pas.' % (self.title), + u'Pièce jointe invalide') self.filename = row[0] self.description = row[1] self.size = row[2] and int(row[2]) or 0 @@ -130,7 +130,7 @@ title = property(_get_title) def delete(self, db=None): - assert self.filename, 'Cannot delete non-existent attachment' + assert self.filename, u'Impossible de supprimer une pièce jointe inexistante' if not db: db = self.env.get_db_cnx() handle_ta = True @@ -149,7 +149,7 @@ self.path, exc_info=True) if handle_ta: db.rollback() - raise TracError, 'Could not delete attachment' + raise TracError, u'Impossible de supprimer la pièce jointe' self.env.log.info('Attachment removed: %s' % self.title) if handle_ta: @@ -241,7 +241,7 @@ except OSError: env.log.error("Can't delete attachment directory %s", attachment_dir, exc_info=True) - + select = classmethod(select) delete_all = classmethod(delete_all) @@ -250,7 +250,7 @@ try: fd = open(self.path, 'rb') except IOError: - raise TracError('Attachment %s not found' % self.filename) + raise TracError(u'Pièce jointe %s non trouvée' % self.filename) return fd @@ -259,7 +259,7 @@ def attachments_to_hdf(env, req, db, parent_type, parent_id): return [attachment_to_hdf(env, req, db, attachment) for attachment in Attachment.select(env, parent_type, parent_id, db)] - + def attachment_to_hdf(env, req, db, attachment): if not db: db = env.get_db_cnx() @@ -325,8 +325,8 @@ # IRequestHandler methods def match_request(self, req): - match = re.match(r'^/attachment/(ticket|wiki)(?:[/:](.*))?$', - req.path_info) + what = r'^/attachment/(ticket|%s)(?:[/:](.*))?$' % self.env.wiki_base_url + match = re.match(what, req.path_info) if match: req.args['type'] = match.group(1) req.args['path'] = match.group(2).replace(':', '/') @@ -336,9 +336,9 @@ parent_type = req.args.get('type') path = req.args.get('path') if not parent_type or not path: - raise HTTPBadRequest('Bad request') - if not parent_type in ['ticket', 'wiki']: - raise HTTPBadRequest('Unknown attachment type') + raise HTTPBadRequest(u'Mauvaise requête') + if not parent_type in ['ticket', self.env.wiki_base_url]: + raise HTTPBadRequest(u'Pièce jointe de type inconnu') action = req.args.get('action', 'view') if action == 'new': @@ -351,7 +351,7 @@ self._render_list(req, parent_type, last_segment) return 'attachment.cs', None if not last_segment: - raise HTTPBadRequest('Bad request') + raise HTTPBadRequest(u'Mauvaise requête') attachment = Attachment(self.env, parent_type, parent_id, last_segment) parent_link, parent_text = self._parent_to_hdf( @@ -376,7 +376,7 @@ # Populate attachment.parent: parent_link = req.href(parent_type, parent_id) if parent_type == 'ticket': - parent_text = 'Ticket #' + parent_id + parent_text = u'Ticket #' + parent_id else: # 'wiki' parent_text = parent_id req.hdf['attachment.parent'] = { @@ -386,7 +386,7 @@ return parent_link, parent_text # IWikiSyntaxProvider methods - + def get_wiki_syntax(self): return [] @@ -427,7 +427,7 @@ href = req.abs_href else: descr = wiki_to_oneliner(descr, self.env, db, shorten=True) - title += Markup(' by %s', author) + title += Markup(u' par %s', author) href = req.href yield('attachment', href.attachment(type, id, filename), title, time, author, descr) @@ -435,7 +435,7 @@ # Internal methods def _do_save(self, req, attachment): - perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY'} + perm_map = {'ticket': 'TICKET_APPEND', self.env.wiki_base_url: 'WIKI_MODIFY'} req.perm.assert_permission(perm_map[attachment.parent_type]) if req.args.has_key('cancel'): @@ -443,7 +443,7 @@ upload = req.args['attachment'] if not hasattr(upload, 'filename') or not upload.filename: - raise TracError('No file uploaded') + raise TracError(u'Aucun fichier reçu') if hasattr(upload.file, 'fileno'): size = os.fstat(upload.file.fileno())[6] else: @@ -451,13 +451,13 @@ size = upload.file.tell() upload.file.seek(0) if size == 0: - raise TracError("Can't upload empty file") + raise TracError(u'Fichier vide') # Maximum attachment size (in bytes) max_size = self.max_size if max_size >= 0 and size > max_size: - raise TracError('Maximum attachment size: %d bytes' % max_size, - 'Upload failed') + raise TracError(u'Taille maximum des pièces attachés: %d octets' % \ + max_size, u'Échec du chargement') # We try to normalize the filename to unicode NFC if we can. # Files uploaded from OS X might be in NFD. @@ -466,7 +466,7 @@ filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) if not filename: - raise TracError('No file uploaded') + raise TracError(u'Aucun fichier reçu') attachment.description = req.args.get('description', '') attachment.author = get_reporter_id(req, 'author') @@ -476,10 +476,10 @@ for manipulator in self.manipulators: for field, message in manipulator.validate_attachment(req, attachment): if field: - raise InvalidAttachment('Attachment field %s is invalid: %s' + raise InvalidAttachment(u'Le champ attaché %s n\'est pas valable: %s' % (field, message)) else: - raise InvalidAttachment('Invalid attachment: %s' % message) + raise InvalidAttachment(u'Pièce jointe non valable : %s' % message) if req.args.get('replace'): try: @@ -487,7 +487,7 @@ attachment.parent_id, filename) if not (old_attachment.author and req.authname \ and old_attachment.author == req.authname): - perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'} + perm_map = {'ticket': 'TICKET_ADMIN', self.env.wiki_base_url: 'WIKI_DELETE'} req.perm.assert_permission(perm_map[old_attachment.parent_type]) old_attachment.delete() except TracError: @@ -499,7 +499,7 @@ req.redirect(attachment.href(req)) def _do_delete(self, req, attachment): - perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'} + perm_map = {'ticket': 'TICKET_ADMIN', self.env.wiki_base_url: 'WIKI_DELETE'} req.perm.assert_permission(perm_map[attachment.parent_type]) if req.args.has_key('cancel'): @@ -511,22 +511,22 @@ req.redirect(attachment.parent_href(req)) def _render_confirm(self, req, attachment): - perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'} + perm_map = {'ticket': 'TICKET_ADMIN', self.env.wiki_base_url: 'WIKI_DELETE'} req.perm.assert_permission(perm_map[attachment.parent_type]) - req.hdf['title'] = '%s (delete)' % attachment.title + req.hdf['title'] = u'%s (suppression)' % attachment.title req.hdf['attachment'] = {'filename': attachment.filename, 'mode': 'delete'} def _render_form(self, req, attachment): - perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY'} + perm_map = {'ticket': 'TICKET_APPEND', self.env.wiki_base_url: 'WIKI_MODIFY'} req.perm.assert_permission(perm_map[attachment.parent_type]) req.hdf['attachment'] = {'mode': 'new', 'author': get_reporter_id(req)} def _render_view(self, req, attachment): - perm_map = {'ticket': 'TICKET_VIEW', 'wiki': 'WIKI_VIEW'} + perm_map = {'ticket': 'TICKET_VIEW', self.env.wiki_base_url: 'WIKI_VIEW'} req.perm.assert_permission(perm_map[attachment.parent_type]) req.check_modified(attachment.time) @@ -539,7 +539,7 @@ req.hdf['attachment.description'] = wiki_to_html(attachment.description, self.env, req) - perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'} + perm_map = {'ticket': 'TICKET_ADMIN', self.env.wiki_base_url: 'WIKI_DELETE'} if req.perm.has_permission(perm_map[attachment.parent_type]): req.hdf['attachment.can_delete'] = 1 @@ -550,7 +550,7 @@ # MIME type detection str_data = fd.read(1000) fd.seek(0) - + binary = is_binary(str_data) mime_type = mimeview.get_mimetype(attachment.filename, str_data) @@ -559,7 +559,7 @@ if format in ('raw', 'txt'): if not self.render_unsafe_content: # Force browser to download files instead of rendering - # them, since they might contain malicious code enabling + # them, since they might contain malicious code enabling # XSS attacks req.send_header('Content-Disposition', 'attachment') if format == 'txt': @@ -573,15 +573,15 @@ req.send_file(attachment.path, mime_type) # add ''Plain Text'' alternate link if needed - if (self.render_unsafe_content and + if (self.render_unsafe_content and mime_type and not mime_type.startswith('text/plain')): plaintext_href = attachment.href(req, format='txt') - add_link(req, 'alternate', plaintext_href, 'Plain Text', + add_link(req, 'alternate', plaintext_href, u'Text Standard', mime_type) # add ''Original Format'' alternate link (always) raw_href = attachment.href(req, format='raw') - add_link(req, 'alternate', raw_href, 'Original Format', mime_type) + add_link(req, 'alternate', raw_href, u'Format original', mime_type) self.log.debug("Rendering preview of file %s with mime-type %s" % (attachment.filename, mime_type)) @@ -608,7 +608,7 @@ else: # FIXME: the formatter should know which object the text being # formatter belongs to - parent_type, parent_id = 'wiki', 'WikiStart' + parent_type, parent_id = self.env.wiki_base_url, 'WikiStart' if formatter.req: path_info = formatter.req.path_info.split('/', 2) if len(path_info) > 1: @@ -622,7 +622,7 @@ if formatter.req: href = attachment.href(formatter.req) + params return html.A(label, class_='attachment', href=href, - title='Attachment %s' % attachment.title) + title=u'Pièce jointe %s' % attachment.title) except TracError: return html.A(label, class_='missing attachment', rel='nofollow', href=formatter.href()) diff --exclude=.svn -Naur trac-0.10.4/trac/config.py trac-0.10.4-PKG/trac/config.py --- trac-0.10.4/trac/config.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/config.py 2007-08-24 10:40:41.000000000 +0200 @@ -30,7 +30,7 @@ 'ExtensionOption', 'OrderedExtensionsOption', 'ConfigurationError', 'default_dir'] -_TRUE_VALUES = ('yes', 'true', 'on', 'aye', '1', 1, True) +_TRUE_VALUES = ('yes', 'oui', 'true', 'vrai', 'on', 'aye', '1', 1, True) class ConfigurationError(TracError): @@ -72,20 +72,20 @@ def getbool(self, section, name, default=None): """Return the specified option as boolean value. - + If the value of the option is one of "yes", "true", "on", or "1", this method wll return `True`, otherwise `False`. - + (since Trac 0.9.3) """ return self[section].getbool(name, default) def getint(self, section, name, default=None): """Return the value of the specified option as integer. - + If the specified option can not be converted to an integer, a `ConfigurationError` exception is raised. - + (since Trac 0.10) """ return self[section].getint(name, default) @@ -93,25 +93,25 @@ def getlist(self, section, name, default=None, sep=',', keep_empty=False): """Return a list of values that have been specified as a single comma-separated option. - + A different separator can be specified using the `sep` parameter. If the `keep_empty` parameter is set to `True`, empty elements are included in the list. - + (since Trac 0.10) """ return self[section].getlist(name, default, sep, keep_empty) def set(self, section, name, value): """Change a configuration value. - + These changes are not persistent unless saved with `save()`. """ self[section].set(name, value) def defaults(self): """Returns a dictionary of the default configuration values. - + (since Trac 0.10) """ defaults = {} @@ -122,7 +122,7 @@ def options(self, section): """Return a list of `(name, value)` tuples for every option in the specified section. - + This includes options that have default values that haven't been overridden. """ @@ -194,7 +194,7 @@ class Section(object): """Proxy for a specific configuration section. - + Objects of this class should not be instantiated directly. """ __slots__ = ['config', 'name', 'overridden'] @@ -206,7 +206,7 @@ def __contains__(self, name): return self.config.parser.has_option(self.name, name) or \ - self.config.site_parser.has_option(self.name, name) + self.config.site_parser.has_option(self.name, name) def __iter__(self): options = [] @@ -240,7 +240,7 @@ def getbool(self, name, default=None): """Return the value of the specified option as boolean. - + This method returns `True` if the option value is one of "yes", "true", "on", or "1", ignoring case. Otherwise `False` is returned. """ @@ -251,7 +251,7 @@ def getint(self, name, default=None): """Return the value of the specified option as integer. - + If the specified option can not be converted to an integer, a `ConfigurationError` exception is raised. """ @@ -261,12 +261,12 @@ try: return int(value) except ValueError: - raise ConfigurationError('expected integer, got %s' % repr(value)) + raise ConfigurationError(u'entier attendu, obtenu %s' % repr(value)) def getlist(self, name, default=None, sep=',', keep_empty=True): """Return a list of values that have been specified as a single comma-separated option. - + A different separator can be specified using the `sep` parameter. If the `skip_empty` parameter is set to `True`, empty elements are omitted from the list. @@ -287,7 +287,7 @@ def set(self, name, value): """Change a configuration value. - + These changes are not persistent unless saved with `save()`. """ if not self.config.parser.has_section(self.name): @@ -308,7 +308,7 @@ def __init__(self, section, name, default=None, doc=''): """Create the extension point. - + @param section: the name of the configuration section this option belongs to @param name: the name of the option @@ -332,7 +332,7 @@ return None def __set__(self, instance, value): - raise AttributeError, 'can\'t set attribute' + raise AttributeError, u'Impossible de définir un attribut' def __repr__(self): return '<%s [%s] "%s">' % (self.__class__.__name__, self.section, @@ -376,9 +376,9 @@ for impl in self.xtnpt.extensions(instance): if impl.__class__.__name__ == value: return impl - raise AttributeError('Cannot find an implementation of the "%s" ' - 'interface named "%s". Please update the option ' - '%s.%s in trac.ini.' + raise AttributeError(u'Impossible de trouver une implémentation d\'interface "%s" ' + u'nommée "%s". Mettez à jour l\'option ' + u'%s.%s dans trac.ini.' % (self.xtnpt.interface.__name__, value, self.section, self.name)) diff --exclude=.svn -Naur trac-0.10.4/trac/core.py trac-0.10.4-PKG/trac/core.py --- trac-0.10.4/trac/core.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/core.py 2007-08-24 10:41:13.000000000 +0200 @@ -39,7 +39,7 @@ def __init__(self, interface): """Create the extension point. - + @param interface: the `Interface` subclass that defines the protocol for the extension point """ @@ -61,7 +61,7 @@ class ComponentMeta(type): """Meta class for components. - + Takes care of component and extension point registration. """ _components = [] @@ -174,11 +174,11 @@ component = self.components.get(cls) if not component: if cls not in ComponentMeta._components: - raise TracError, 'Component "%s" not registered' % cls.__name__ + raise TracError, u'Composant "%s" non enregistré' % cls.__name__ try: component = cls(self) except TypeError, e: - raise TracError, 'Unable to instantiate component %r (%s)' \ + raise TracError, u"Impossible d'instancier le composant %r (%s)" \ % (cls, e) return component diff --exclude=.svn -Naur trac-0.10.4/trac/db/api.py trac-0.10.4-PKG/trac/db/api.py --- trac-0.10.4/trac/db/api.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/db/api.py 2007-08-24 10:45:06.000000000 +0200 @@ -40,7 +40,7 @@ def get_connection(**kwargs): """Create a new connection to the database.""" - + def init_db(**kwargs): """Initialize the database.""" @@ -94,7 +94,7 @@ candidates[scheme] = (connector, priority) connector = candidates.get(scheme, [None])[0] if not connector: - raise TracError('Unsupported database type "%s"' % scheme) + raise TracError(u'Base de données de type "%s" non supportée' % scheme) if scheme == 'sqlite': # Special case for SQLite to support a path relative to the @@ -116,8 +116,8 @@ host = None path = rest else: - raise TracError('Database connection string must start with ' - 'scheme:/') + raise TracError(u'La chaîne %s de connexion à la base de données "%s" ' + u'doit commencer par scheme:/' % db_str) else: if rest.startswith('/') and not rest.startswith('//'): host = None diff --exclude=.svn -Naur trac-0.10.4/trac/db/mysql_backend.py trac-0.10.4-PKG/trac/db/mysql_backend.py --- trac-0.10.4/trac/db/mysql_backend.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/db/mysql_backend.py 2007-08-24 10:46:47.000000000 +0200 @@ -1,4 +1,4 @@ -# -*- coding: iso8859-1 -*- +# -*- coding: utf-8 -*- # # Copyright (C) 2005-2006 Edgewall Software # Copyright (C) 2005-2006 Christopher Lenz @@ -122,7 +122,8 @@ def _set_character_set(self, cnx, charset): vers = tuple([ int(n) for n in cnx.get_server_info().split('.')[:2] ]) if vers < (4, 1): - raise TracError, 'MySQL servers older than 4.1 are not supported!' + raise TracError, u'Les serveurs MySQL antérieurs à 4.1 ne sont ' \ + u'pas supportés!' cnx.query('SET NAMES %s' % charset) cnx.store_result() cnx.charset = charset diff --exclude=.svn -Naur trac-0.10.4/trac/db/pool.py trac-0.10.4-PKG/trac/db/pool.py --- trac-0.10.4/trac/db/pool.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/db/pool.py 2007-08-24 10:48:02.000000000 +0200 @@ -50,7 +50,7 @@ def try_rollback(cnx): """Resets the Connection in a safe way, returning True when it succeeds. - + The rollback we do for safety on a Connection can fail at critical times because of a timeout on the Connection. """ @@ -104,9 +104,9 @@ else: if timeout: if (time.time() - start) >= timeout: - raise TimeoutError('Unable to get database ' - 'connection within %d seconds' - % timeout) + raise TimeoutError(u'Impossible de se connecter à' + u' la base de données sous %d ' + u'secondes' % timeout) self._available.wait(timeout) else: # Warning: without timeout, Trac *might* hang self._available.wait() diff --exclude=.svn -Naur trac-0.10.4/trac/db/sqlite_backend.py trac-0.10.4-PKG/trac/db/sqlite_backend.py --- trac-0.10.4/trac/db/sqlite_backend.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/db/sqlite_backend.py 2007-08-24 10:50:01.000000000 +0200 @@ -116,7 +116,7 @@ if path != ':memory:': # make the directory to hold the database if os.path.exists(path): - raise TracError, 'Database already exists at %s' % path + raise TracError, u'Une base de donnée existe déjà sur %s' % path os.makedirs(os.path.split(path)[0]) cnx = sqlite.connect(path, timeout=int(params.get('timeout', 10000))) cursor = cnx.cursor() @@ -141,15 +141,16 @@ self.cnx = None if path != ':memory:': if not os.access(path, os.F_OK): - raise TracError, 'Database "%s" not found.' % path + raise TracError, u'Base de données "%s" non trouvée.' % path dbdir = os.path.dirname(path) if not os.access(path, os.R_OK + os.W_OK) or \ not os.access(dbdir, os.R_OK + os.W_OK): from getpass import getuser - raise TracError('The user %s requires read _and_ write ' \ - 'permission to the database file %s and the ' \ - 'directory it is located in.' \ + raise TracError(u"L'utilisateur %s a besoin des permissions " + u"en lecture _et_ en écriture sur la base de " + u"données %s ainsi que sur le répertoire " + u"dans lequel elle est située." % (getuser(), path)) if have_pysqlite == 2: @@ -161,7 +162,7 @@ else: timeout = int(params.get('timeout', 10000)) cnx = sqlite.connect(path, timeout=timeout, encoding='utf-8') - + ConnectionWrapper.__init__(self, cnx) if have_pysqlite == 2: diff --exclude=.svn -Naur trac-0.10.4/trac/db_default.py trac-0.10.4-PKG/trac/db_default.py --- trac-0.10.4/trac/db_default.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/db_default.py 2007-10-19 14:43:33.000000000 +0200 @@ -117,7 +117,7 @@ Column('description'), Column('keywords'), Index(['time']), - Index(['status'])], + Index(['status'])], Table('ticket_change', key=('ticket', 'time', 'field'))[ Column('ticket', type='int'), Column('time', type='int'), @@ -166,72 +166,72 @@ def get_reports(db): owner = db.concat('owner', "' *'") return ( -('Active Tickets', -""" - * List all active tickets by priority. - * Color each row based on priority. - * If a ticket has been accepted, a '*' is appended after the owner's name +('Tickets ouverts', +u""" + * Liste de tous les tickets ouverts triés par priorité. + * Les couleurs de lignes sont basées sur la priorité. + * Si un ticket a été accepté, un '*' est accolé au nom du propriétaire du ticket. """, """ SELECT p.value AS __color__, - id AS ticket, summary, component, version, milestone, t.type AS type, + id AS ticket, summary, component, version, milestone, t.type AS type, (CASE status WHEN 'assigned' THEN %s ELSE owner END) AS owner, time AS created, changetime AS _changetime, description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' - WHERE status IN ('new', 'assigned', 'reopened') + WHERE status IN ('new', 'assigned', 'reopened') ORDER BY p.value, milestone, t.type, time """ % owner), #---------------------------------------------------------------------------- - ('Active Tickets by Version', -""" -This report shows how to color results by priority, -while grouping results by version. + ('Tickets ouverts par Version', +u""" +Ce rapport montre comment mettre en valeur avec des couleurs les +résultats triés par priorité, quand ils sont aussi groupés par version. -Last modification time, description and reporter are included as hidden fields -for useful RSS export. +La date de dernière modification, la description et le rapporteur sont aussi +inclus comme champs cachés pour une meilleure exportation en flux RSS. """, """ SELECT p.value AS __color__, version AS __group__, - id AS ticket, summary, component, version, t.type AS type, + id AS ticket, summary, component, version, t.type AS type, (CASE status WHEN 'assigned' THEN %s ELSE owner END) AS owner, time AS created, changetime AS _changetime, description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' - WHERE status IN ('new', 'assigned', 'reopened') + WHERE status IN ('new', 'assigned', 'reopened') ORDER BY (version IS NULL),version, p.value, t.type, time """ % owner), #---------------------------------------------------------------------------- -('Active Tickets by Milestone', -""" -This report shows how to color results by priority, -while grouping results by milestone. +('Tous les Tickets par Objectif', +u""" +Ce rapport montre comment mettre en valeur avec des couleurs les +résultats triés par priorité, quand ils sont aussi groupés par objectif. -Last modification time, description and reporter are included as hidden fields -for useful RSS export. +La date de dernière modification, la description et le rapporteur sont aussi +inclus comme champs cachés pour une meilleure exportation en flux RSS. """, """ SELECT p.value AS __color__, - %s AS __group__, - id AS ticket, summary, component, version, t.type AS type, + 'Objectif : '||milestone AS __group__, + id AS ticket, summary, component, version, t.type AS type, (CASE status WHEN 'assigned' THEN %s ELSE owner END) AS owner, time AS created, changetime AS _changetime, description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' - WHERE status IN ('new', 'assigned', 'reopened') + WHERE status IN ('new', 'assigned', 'reopened') ORDER BY (milestone IS NULL),milestone, p.value, t.type, time -""" % (db.concat('milestone', "' Release'"), owner)), +""" % owner ), #---------------------------------------------------------------------------- -('Assigned, Active Tickets by Owner', -""" -List assigned tickets, group by ticket owner, sorted by priority. +(u'Tickets assignés et ouverts par Propriétaire', +u""" +Liste des tickets assignés, groupés par propriétaire et triés par priorité. """, """ @@ -246,10 +246,10 @@ ORDER BY owner, p.value, t.type, time """), #---------------------------------------------------------------------------- -('Assigned, Active Tickets by Owner (Full Description)', -""" -List tickets assigned, group by ticket owner. -This report demonstrates the use of full-row display. +(u'Tickets assignés et ouverts par Propriétaire (Description complète)', +u""" +Liste des tickets assignés, groupés par propriétaire et triés par priorité. +Ce rapport démontre l'utilisation de la fonction ligne complète. """, """ SELECT p.value AS __color__, @@ -263,37 +263,37 @@ ORDER BY owner, p.value, t.type, time """), #---------------------------------------------------------------------------- -('All Tickets By Milestone (Including closed)', -""" -A more complex example to show how to make advanced reports. +(u'Tous les Tickets par Objectif (fermés inclus)', +u""" +Un exemple plus complexe pour démontrer comme faire des rapports avancés. """, """ SELECT p.value AS __color__, t.milestone AS __group__, - (CASE status + (CASE status WHEN 'closed' THEN 'color: #777; background: #ddd; border-color: #ccc;' - ELSE + ELSE (CASE owner WHEN $USER THEN 'font-weight: bold' END) END) AS __style__, - id AS ticket, summary, component, status, + id AS ticket, summary, component, status, resolution,version, t.type AS type, priority, owner, changetime AS modified, time AS _time,reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' - ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'), - (CASE status WHEN 'closed' THEN modified ELSE (-1)*p.value END) DESC + ORDER BY (milestone IS NULL), milestone DESC, (status = 'closed'), + (CASE status WHEN 'closed' THEN changetime ELSE (-1)*p.value END) DESC """), #---------------------------------------------------------------------------- -('My Tickets', -""" -This report demonstrates the use of the automatically set -USER dynamic variable, replaced with the username of the -logged in user when executed. +('Mes Tickets', +u""" +Ce rapport démontre l'utilisation de la variable dynamique +USER définie automatiquement, pour remplacer le nom d'utilisateur +par le nom de l'utilisateur connecté quand la requête est exécutée. """, -""" +u""" SELECT p.value AS __color__, - (CASE status WHEN 'assigned' THEN 'Assigned' ELSE 'Owned' END) AS __group__, + (CASE status WHEN 'assigned' THEN 'Acceptés' ELSE 'Assignés' END) AS __group__, id AS ticket, summary, component, version, milestone, t.type AS type, priority, time AS created, changetime AS _changetime, description AS _description, @@ -304,25 +304,25 @@ ORDER BY (status = 'assigned') DESC, p.value, milestone, t.type, time """), #---------------------------------------------------------------------------- -('Active Tickets, Mine first', -""" - * List all active tickets by priority. - * Show all tickets owned by the logged in user in a group first. +(u'Tickets ouverts, les miens d\'abord', +u""" + * Liste de tous les tickets ouverts triés par priorité. + * Montre tous les tickets de l'utilisateur connecté groupés en premier """, """ SELECT p.value AS __color__, - (CASE owner - WHEN $USER THEN 'My Tickets' - ELSE 'Active Tickets' + (CASE owner + WHEN $USER THEN 'Mes Tickets' + ELSE 'Tickets ouverts' END) AS __group__, - id AS ticket, summary, component, version, milestone, t.type AS type, + id AS ticket, summary, component, version, milestone, t.type AS type, (CASE status WHEN 'assigned' THEN %s ELSE owner END) AS owner, time AS created, changetime AS _changetime, description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority' - WHERE status IN ('new', 'assigned', 'reopened') + WHERE status IN ('new', 'assigned', 'reopened') ORDER BY (owner = $USER) DESC, p.value, milestone, t.type, time """ % owner)) diff --exclude=.svn -Naur trac-0.10.4/trac/env.py trac-0.10.4-PKG/trac/env.py --- trac-0.10.4/trac/env.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/env.py 2007-08-29 17:56:33.000000000 +0200 @@ -36,14 +36,14 @@ def environment_needs_upgrade(db): """Called when Trac checks whether the environment needs to be upgraded. - + Should return `True` if this participant needs an upgrade to be performed, `False` otherwise. """ def upgrade_environment(db): """Actually perform an environment upgrade. - + Implementations of this method should not commit any database transactions. This is done implicitly after all participants have performed the upgrades they need without an error being raised. @@ -59,12 +59,15 @@ * an SQLite database (stores tickets, wiki pages...) * Project specific templates and wiki macros. * wiki and ticket attachments. - """ + """ setup_participants = ExtensionPoint(IEnvironmentSetupParticipant) + wiki_base_url = Option('trac', 'wiki_base_url', 'wiki', + """Option PKG pour changer le terme 'wiki' des URLs""") + base_url = Option('trac', 'base_url', '', """Base URL of the Trac deployment. - + In most configurations, Trac will automatically reconstruct the URL that is used to access it automatically. However, in more complex setups, usually involving running Trac behind a HTTP proxy, you may @@ -80,7 +83,7 @@ """URL of the main project web site.""") project_footer = Option('project', 'footer', - 'Visit the Trac open source project at
    ' + 'Visitez le projet Trac open source à
    ' '' 'http://trac.edgewall.org/', """Page footer text (right-aligned).""") @@ -90,7 +93,7 @@ log_type = Option('logging', 'log_type', 'none', """Logging facility to use. - + Should be one of (`none`, `file`, `stderr`, `syslog`, `winlog`).""") log_file = Option('logging', 'log_file', 'trac.log', @@ -98,14 +101,14 @@ log_level = Option('logging', 'log_level', 'DEBUG', """Level of verbosity in log. - + Should be one of (`CRITICAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`).""") log_format = Option('logging', 'log_format', None, """Custom logging format. If nothing is set, the following will be used: - + Trac[$(module)s] $(levelname)s: $(message)s In addition to regular key names supported by the Python logger library @@ -122,9 +125,55 @@ (since 0.11)""") + tr_fixed = Option('translation', 'fixed', u'corrigé') + tr_invalid = Option('translation', 'invalid', u'invalide') + tr_wontfix = Option('translation', 'wontfix', u'noncorrigible') + tr_duplicate = Option('translation', 'duplicate', u'doublon') + tr_worksforme = Option('translation', 'worksforme', u'nonreproductible') + tr_new = Option('translation', 'new', u'nouveau') + tr_closed = Option('translation', 'closed', u'fermé') + tr_assigned = Option('translation', 'assigned', u'assigné') + tr_reopened = Option('translation', 'reopened', u'réouvert') + tr_reassign = Option('translation', 'reassign', u'réassigné') + tr_blocker = Option('translation', 'blocker', u'bloquante') + tr_critical = Option('translation', 'critical', u'critique') + tr_major = Option('translation', 'major', u'majeure') + tr_minor = Option('translation', 'minor', u'mineure') + tr_trivial = Option('translation', 'trivial', u'triviale') + tr_defect = Option('translation', 'defect', u'défaut') + tr_enhancement = Option('translation', 'enhancement', u'amélioration') + tr_task = Option('translation', 'task', u'tâche') + tr_component = Option('translation', 'component', u'composant') + tr_keywords = Option('translation', 'keywords', u'mots clefs') + tr_priority = Option('translation', 'priority', u'priorité') + tr_milestone = Option('translation', 'milestone', u'objectif') + tr_summary = Option('translation', 'summary', u'intitulé') + tr_resolution = Option('translation', 'resolution', u'résolution') + tr_report = Option('translation', 'report', u'rapport') + tr_title = Option('translation', 'title', u'titre') + tr_owner = Option('translation', 'owner', u'propriétaire') + tr_reporter = Option('translation', 'reporter', u'rapporteur') + tr_created = Option('translation', 'created', u'créé') + tr_modified = Option('translation', 'modified', u'modifié') + tr_change = Option('translation', 'change', u'modification') + tr_changeset = Option('translation', 'changeset', u'version') + tr_status = Option('translation', 'status', u'statut') + tr_version = Option('translation', 'version', u'version') + tr_cc = Option('translation', 'cc', u'cc') + tr_line = Option('translation', 'line', u'ligne') + tr_reply = Option('translation', 'reply', u'répondre') + tr_wiki = Option('translation', 'wiki', 'documentation') + tr_roadmap = Option('translation', 'roadmap', u'feuille de route') + tr_of_Roadmap = Option('translation', 'of_Roadmap', u'de la Feuille de route') + tr_new_milestone = Option('translation', 'new_milestone', u'nouvel objectif') + tr_newMilestone = Option('translation', 'new_Milestone', u'nouvel Objectif') + tr_the_milestone = Option('translation', 'the_milestone', u'l\'objectif') + tr_thisMilestone = Option('translation', 'this_milestone', u'cet objectif') + tr_of_milestone = Option('translation', 'of_milestone', u'de l\'objectif') + def __init__(self, path, create=False, options=[]): """Initialize the Trac environment. - + @param path: the absolute path to the Trac environment @param create: if `True`, the environment is created and populated with default data; otherwise, the environment is expected to @@ -145,6 +194,8 @@ self.create(options) else: self.verify() + # Translations initialization + self.init_translations() if create: for setup_participant in self.setup_participants: @@ -152,7 +203,7 @@ def component_activated(self, component): """Initialize additional member variables for components. - + Every component activated through the `Environment` object gets three member variables: `env` (the environment object), `config` (the environment configuration) and `log` (a logger object).""" @@ -163,7 +214,7 @@ def is_component_enabled(self, cls): """Implemented to only allow activation of components that are not disabled in the configuration. - + This is called by the `ComponentManager` base class when a component is about to be activated. If this method returns false, the component does not get activated.""" @@ -210,7 +261,7 @@ def get_repository(self, authname=None): """Return the version control repository configured for this environment. - + @param authname: user name for authorization """ return RepositoryManager(self).get_repository(authname) @@ -235,8 +286,8 @@ _create_file(os.path.join(self.path, 'VERSION'), 'Trac Environment Version 1\n') _create_file(os.path.join(self.path, 'README'), - 'This directory contains a Trac environment.\n' - 'Visit http://trac.edgewall.org/ for more information.\n') + u'Ce dossier contient un environnement Trac.\n' + u'Veuillez visiter http://trac.edgewall.org/ pour plus d\'informations.\n') # Setup the default configuration os.mkdir(os.path.join(self.path, 'conf')) @@ -268,6 +319,24 @@ value = None self.config.set(section, name, value) + def init_translations(self): + self.translations = {} + + # Charger d'abord les valeurs par défaut + for section, default_options in self.config.defaults().iteritems(): + if section == 'translation': + for name, value in default_options.iteritems(): + # Ne garder la valeur par défaut que si elle n'est pas déjà + # redéfinie dans la configuration + if self.config.get('translation', name) == value: + self.config.set(section, name, value) + + for (k,v) in self.config.options('translation'): + self.translations[k] = v + ck = k.capitalize() + cv = v.capitalize() + self.translations[ck] = cv + def get_templates_dir(self): """Return absolute path to the templates directory.""" return os.path.join(self.path, 'templates') @@ -330,7 +399,8 @@ db_str = self.config.get('trac', 'database') if not db_str.startswith('sqlite:'): - raise EnvironmentError('Can only backup sqlite databases') + raise EnvironmentError(u'Seules les bases de données sqlite ' + u'peuvent être sauvegardées') db_name = os.path.join(self.path, db_str[7:]) if not dest: dest = '%s.%i.bak' % (db_name, self.get_version()) @@ -348,7 +418,7 @@ def upgrade(self, backup=False, backup_dest=None): """Upgrade database. - + Each db version should have its own upgrade module, names upgrades/dbN.py, where 'N' is the version number (int). @@ -398,7 +468,8 @@ if dbver == db_default.db_version: return False elif dbver > db_default.db_version: - raise TracError, 'Database newer than Trac version' + raise TracError, u'Base de données plus récentes que la version ' \ + u'de Trac' return True def upgrade_environment(self, db): @@ -410,7 +481,8 @@ upgrades = __import__('upgrades', globals(), locals(), [name]) script = getattr(upgrades, name) except AttributeError: - err = 'No upgrade module for version %i (%s.py)' % (i, name) + err = u'Pas de module de mise à jour pour la version %i ' \ + u'(%s.py)' % (i, name) raise TracError, err script.do_upgrade(self.env, i, cursor) cursor.execute("UPDATE system SET value=%s WHERE " @@ -427,6 +499,8 @@ for section, options in self.config.defaults().items(): config.add_section(section) for name, value in options.items(): + if isinstance(value, unicode): + value = value.encode('utf8') config.set(section, name, value) filename = os.path.join(self.env.path, 'conf', 'trac.ini.sample') try: @@ -455,12 +529,12 @@ if not env_path: env_path = os.getenv('TRAC_ENV') if not env_path: - raise TracError, 'Missing environment variable "TRAC_ENV". Trac ' \ - 'requires this variable to point to a valid Trac ' \ - 'environment.' + raise TracError, \ + 'La variable d\'environment "TRAC_ENV" n\'est pas définie. Trac a ' \ + 'besoin que cette variable pointe sur un environnement Trac valide.' env = Environment(env_path) if env.needs_upgrade(): - raise TracError, 'The Trac Environment needs to be upgraded. Run ' \ - 'trac-admin %s upgrade"' % env_path + raise TracError, u"L'environment Trac doit être mis à jour. Utilisez " \ + u"trac-admin %s upgrade" % env_path return env diff --exclude=.svn -Naur trac-0.10.4/trac/log.py trac-0.10.4-PKG/trac/log.py --- trac-0.10.4/trac/log.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/log.py 2007-08-21 17:33:35.000000000 +0200 @@ -44,7 +44,7 @@ format = '%(asctime)s ' + format datefmt = '' if logtype == 'stderr': - datefmt = '%X' + datefmt = '%D %X' level = level.upper() if level in ('DEBUG', 'ALL'): logger.setLevel(logging.DEBUG) @@ -58,6 +58,6 @@ logger.setLevel(logging.WARNING) formatter = logging.Formatter(format, datefmt) hdlr.setFormatter(formatter) - logger.addHandler(hdlr) + logger.addHandler(hdlr) return logger diff --exclude=.svn -Naur trac-0.10.4/trac/mimeview/api.py trac-0.10.4-PKG/trac/mimeview/api.py --- trac-0.10.4/trac/mimeview/api.py 2007-04-20 15:41:45.000000000 +0200 +++ trac-0.10.4-PKG/trac/mimeview/api.py 2007-10-19 12:57:29.000000000 +0200 @@ -80,14 +80,14 @@ 'application/x-csh': ['csh'], 'application/x-troff': ['nroff', 'roff', 'troff'], 'application/x-yaml': ['yml', 'yaml'], - + 'application/rss+xml': ['rss'], - + 'image/x-icon': ['ico'], 'image/svg+xml': ['svg'], - + 'model/vrml': ['vrml', 'wrl'], - + 'text/css': ['css'], 'text/html': ['html'], 'text/plain': ['txt', 'TXT', 'text', 'README', 'INSTALL', @@ -147,7 +147,7 @@ `filename` is either a filename (the lookup will then use the suffix) or some arbitrary keyword. - + `content` is either a `str` or an `unicode` string. """ suffix = filename.split('.')[-1] @@ -249,7 +249,7 @@ be available through the `filename` or `url` parameters. This is useful for renderers that embed objects, using or instead of including the content inline. - + Can return the generated XHTML text as a single string or as an iterable that yields strings. In the latter case, the list will be considered to correspond to lines of text in the original content. @@ -279,21 +279,21 @@ ---- NOTE: This api will likely change in the future, e.g.: - def get_supported_conversions(input): + def get_supported_conversions(input): '''Tells whether this converter can handle this `input` type. Return an iterable of `Conversion` objects, each describing how the conversion should be done and what will be the output type. ''' - def convert_content(context, conversion, content): + def convert_content(context, conversion, content): '''Convert the given `AbstractContent` as specified by `Conversion`. The conversion takes place in the given formatting `context`. A `context` provides at least a `req` property. If no other specific context object is available, a `ToplevelContext` can be used to wrap the `req` instance. - + Return the converted content, which ''must'' be a `MimeContent` object. ''' ---- @@ -338,7 +338,7 @@ def __init__(self): self._mime_map = None - + # Public API def get_supported_conversions(self, mimetype): @@ -376,7 +376,7 @@ candidates = list(self.get_supported_conversions(mimetype)) candidates = [c for c in candidates if key in (c[0], c[4])] if not candidates: - raise TracError('No available MIME conversions from %s to %s' % + raise TracError(u'Aucune conversion MIME supportée de %s à %s' % (mimetype, key)) # First successful conversion wins @@ -386,7 +386,7 @@ if not output: continue return (output[0], output[1], ext) - raise TracError('No available MIME conversions from %s to %s' % + raise TracError(u'Aucune conversion MIME supportée de %s à %s' % (mimetype, key)) def get_annotation_types(self): @@ -464,7 +464,7 @@ return Markup(buf.getvalue()) except Exception, e: self.log.warning('HTML preview using %s failed (%s)' - % (renderer, e), exc_info=True) + % (renderer, to_unicode(e)), exc_info=True) def _annotate(self, lines, annotations): buf = StringIO() @@ -508,11 +508,11 @@ """Infer the character encoding from the `content` or the `mimetype`. `content` is either a `str` or an `unicode` object. - + The charset will be determined using this order: * from the charset information present in the `mimetype` argument * auto-detection of the charset from the `content` - * the configured `default_charset` + * the configured `default_charset` """ if mimetype: ctpos = mimetype.find('charset=') @@ -580,13 +580,13 @@ self.log.warning("Invalid mapping '%s' specified in '%s' " "option." % (mapping, option)) return types - + def preview_to_hdf(self, req, content, length, mimetype, filename, url=None, annotations=None): """Prepares a rendered preview of the given `content`. Note: `content` will usually be an object with a `read` method. - """ + """ if length >= self.max_preview_size: return {'max_file_size_reached': True, 'max_file_size': self.max_preview_size, @@ -605,12 +605,12 @@ content, selector) req.send_response(200) req.send_header('Content-Type', output_type) - req.send_header('Content-Disposition', 'attachment; filename=%s.%s' % + req.send_header('Content-Disposition', 'attachment; filename=%s.%s' % (filename, ext)) req.end_headers() req.write(content) - raise RequestDone - + raise RequestDone + def _html_splitlines(lines): """Tracks open and close tags in lines of HTML text and yields lines that @@ -654,7 +654,7 @@ # ITextAnnotator methods def get_annotation_type(self): - return 'lineno', 'Line', 'Line numbers' + return 'lineno', 'Ligne', u'Numérotation des lignes' def annotate_line(self, number, content): return '
    ' % (number, number, diff --exclude=.svn -Naur trac-0.10.4/trac/mimeview/enscript.py trac-0.10.4-PKG/trac/mimeview/enscript.py --- trac-0.10.4/trac/mimeview/enscript.py 2007-04-20 15:41:45.000000000 +0200 +++ trac-0.10.4-PKG/trac/mimeview/enscript.py 2007-10-19 12:33:37.000000000 +0200 @@ -137,8 +137,8 @@ np = NaivePopen(cmdline, content.encode('utf-8'), capturestderr=1) if np.errorlevel or np.err: - err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, - np.err) + err = u"L'exécution de la commande (%s) a echoué: %s, %s." % \ + (cmdline, np.errorlevel, np.err) raise Exception, err odata = np.out diff --exclude=.svn -Naur trac-0.10.4/trac/mimeview/patch.py trac-0.10.4-PKG/trac/mimeview/patch.py --- trac-0.10.4/trac/mimeview/patch.py 2007-04-20 15:41:45.000000000 +0200 +++ trac-0.10.4-PKG/trac/mimeview/patch.py 2007-08-24 11:05:28.000000000 +0200 @@ -35,7 +35,7 @@
    • -
    - Version (modified by , ago) + Version (modifié par , auparavant)
    %s
    +
    @@ -69,7 +69,7 @@ d = self._diff_to_hdf(content.splitlines(), Mimeview(self.env).tab_width) if not d: - raise TracError, 'Invalid unified diff content' + raise TracError, u'Contenu diff unifié invalide' hdf = HDFWrapper(loadpaths=[self.env.get_templates_dir(), self.config.get('trac', 'templates_dir')]) hdf['diff.files'] = d diff --exclude=.svn -Naur trac-0.10.4/trac/mimeview/php.py trac-0.10.4-PKG/trac/mimeview/php.py --- trac-0.10.4/trac/mimeview/php.py 2007-04-20 15:41:45.000000000 +0200 +++ trac-0.10.4-PKG/trac/mimeview/php.py 2007-08-24 11:05:53.000000000 +0200 @@ -41,7 +41,7 @@ # the first span after a set of 1+ "
    " to before them. r_fixeol = re.compile(r"((?:
    )+)()") indata = r_fixeol.sub(lambda m: m.group(2) + m.group(1), indata) - + # Now call superclass implementation that handles the dirty work # of applying css classes. return Deuglifier.format(self, indata) @@ -83,17 +83,16 @@ content = content.encode('utf-8') np = NaivePopen(cmdline, content, capturestderr=1) if (os.name != 'nt' and np.errorlevel) or np.err: - msg = 'Running (%s) failed: %s, %s.' % (cmdline, - np.errorlevel, - np.err) + msg = u'L\'exécution de la commande (%s) a echoué : %s, %s.' \ + % (cmdline, np.errorlevel, np.err) raise Exception(msg) odata = ''.join(np.out.splitlines()[1:-1]) if odata.startswith('X-Powered-By:') or \ odata.startswith('Content-type:'): - raise TracError('You appear to be using the PHP CGI ' - 'binary. Trac requires the CLI version ' - 'for syntax highlighting.') + raise TracError(u'Apparemment, vous utilisez la version CGI de PHP. ' + u'Trac a besoin de la version CLI pour réaliser la ' + u'coloration syntaxique.') epilogues = ["", ""] for e in epilogues: diff --exclude=.svn -Naur trac-0.10.4/trac/mimeview/rst.py trac-0.10.4-PKG/trac/mimeview/rst.py --- trac-0.10.4/trac/mimeview/rst.py 2007-04-20 15:41:45.000000000 +0200 +++ trac-0.10.4-PKG/trac/mimeview/rst.py 2007-08-24 11:07:14.000000000 +0200 @@ -52,9 +52,9 @@ from docutils.parsers import rst from docutils import __version__ except ImportError: - raise TracError, 'Docutils not found' + raise TracError, u'La bibliothèque Docutils est introuvable' if StrictVersion(__version__) < StrictVersion('0.3.9'): - raise TracError, 'Docutils version >= %s required, %s found' \ + raise TracError, u'Une version >= %s de Docutils est requise, la version %s a été détectée' \ % ('0.3.9', __version__) def trac_get_reference(rawtext, target, text): @@ -74,7 +74,7 @@ else: uri = req.href.wiki(target) missing = not WikiSystem(self.env).has_page(target) - if uri: + if uri: reference = nodes.reference(rawtext, text or target) reference['refuri']= uri if missing: @@ -84,8 +84,8 @@ def trac(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): - """Inserts a `reference` node into the document - for a given `TracLink`_, based on the content + """Inserts a `reference` node into the document + for a given `TracLink`_, based on the content of the arguments. Usage:: @@ -113,7 +113,7 @@ # didn't find a match (invalid TracLink), # report a warning warning = state_machine.reporter.warning( - '%s is not a valid TracLink' % (arguments[0]), + u'%s n\'est pas un lien Trac correct' % (arguments[0]), nodes.literal_block(block_text, block_text), line=lineno) return [warning] @@ -130,7 +130,7 @@ if reference: return [reference], [] warning = nodes.warning(None, nodes.literal_block(text, - 'WARNING: %s is not a valid TracLink' % rawtext)) + u'ATTENTION: %s n\'est pas un lien Trac correct' % rawtext)) return warning, [] # 1 required arg, 1 optional arg, spaces allowed in last arg @@ -146,7 +146,7 @@ html = processor.process(req, text) raw = nodes.raw('', html, format='html') return raw - + def code_role(name, rawtext, text, lineno, inliner, options={}, content=[]): language = options.get('language') @@ -159,7 +159,7 @@ text = '' reference = code_formatter(language, text) return [reference], [] - + def code_block(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """ @@ -170,7 +170,7 @@ If the language can be syntax highlighted it will be. """ language = arguments[0] - text = '\n'.join(content) + text = '\n'.join(content) reference = code_formatter(language, text) return [reference] @@ -180,7 +180,7 @@ 1, # Number of required arguments. 0, # Number of optional arguments. 0) # True if final argument may contain whitespace. - + # A mapping from option name to conversion function. code_role.options = code_block.options = { 'language' : @@ -195,7 +195,7 @@ _parser = rst.Parser(inliner=_inliner) content = content_to_unicode(self.env, content, mimetype) parts = publish_parts(content, writer_name='html', parser=_parser, - settings_overrides={'halt_level': 6, - 'file_insertion_enabled': 0, + settings_overrides={'halt_level': 6, + 'file_insertion_enabled': 0, 'raw_enabled': 0}) return parts['html_body'] diff --exclude=.svn -Naur trac-0.10.4/trac/notification.py trac-0.10.4-PKG/trac/notification.py --- trac-0.10.4/trac/notification.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/notification.py 2007-08-24 11:08:57.000000000 +0200 @@ -58,13 +58,13 @@ smtp_always_bcc = Option('notification', 'smtp_always_bcc', '', """Email address(es) to always send notifications to, addresses do not appear publicly (Bcc:). (''since 0.10'').""") - + smtp_default_domain = Option('notification', 'smtp_default_domain', '', """Default host/domain to append to address that do not specify one""") - + mime_encoding = Option('notification', 'mime_encoding', 'base64', """Specifies the MIME encoding scheme for emails. - + Valid options are 'base64' for Base64 encoding, 'qp' for Quoted-Printable, and 'none' for no encoding. Note that the no encoding means that non-ASCII characters in text are going to cause problems @@ -72,31 +72,31 @@ use_public_cc = BoolOption('notification', 'use_public_cc', 'false', """Recipients can see email addresses of other CC'ed recipients. - + If this option is disabled (the default), recipients are put on BCC (''since 0.10'').""") use_short_addr = BoolOption('notification', 'use_short_addr', 'false', """Permit email address without a host/domain (i.e. username only) - + The SMTP server should accept those addresses, and either append a FQDN or use local delivery (''since 0.10'').""") - + use_tls = BoolOption('notification', 'use_tls', 'false', """Use SSL/TLS to send notifications (''since 0.10'').""") - + smtp_subject_prefix = Option('notification', 'smtp_subject_prefix', - '__default__', - """Text to prepend to subject line of notification emails. - + '__default__', + """Text to prepend to subject line of notification emails. + If the setting is not defined, then the [$project_name] prefix. - If no prefix is desired, then specifying an empty option + If no prefix is desired, then specifying an empty option will disable it.(''since 0.10.1'').""") class Notify(object): """Generic notification class for Trac. - + Subclass this to implement different methods. """ @@ -117,7 +117,7 @@ def get_recipients(self, resid): """Return a pair of list of subscribers to the resource 'resid'. - + First list represents the direct recipients (To:), second list represents the recipients in carbon copy (Cc:). """ @@ -125,7 +125,7 @@ def begin_send(self): """Prepare to send messages. - + Called before sending begins. """ @@ -135,7 +135,7 @@ def finish_send(self): """Clean up after sending all messages. - + Called after sending all messages. """ @@ -166,7 +166,7 @@ for username, name, email in self.env.get_known_users(self.db): if email: self.email_map[username] = email - + def _init_pref_encoding(self): from email.Charset import Charset, QP, BASE64 self._charset = Charset() @@ -190,7 +190,7 @@ self._charset.input_codec = None self._charset.output_charset = 'ascii' else: - raise TracError, 'Invalid email encoding setting: %s' % pref + raise TracError, u'Configuration encodage courriel invalide: %s' % pref def notify(self, resid, subject): self.subject = subject @@ -203,11 +203,11 @@ self.replyto_email = self.config['notification'].get('smtp_replyto') self.from_email = self.from_email or self.replyto_email if not self.from_email and not self.replyto_email: - raise TracError(Markup('Unable to send email due to identity ' - 'crisis.

    Neither notification.from ' - 'nor notification.reply_to are ' - 'specified in the configuration.

    '), - 'SMTP Notification Error') + raise TracError(Markup(u'Impossible d\'envoyer un courriel.
    ' + u'Ni notification.from ni' + u' notification.reply_to ne sont' + u' définis dans la configuration.'), + u'Erreur de notification SMTP') # Authentication info (optional) self.user_name = self.config['notification'].get('smtp_user') @@ -220,7 +220,7 @@ maxlength = MAXHEADERLEN-(len(key)+2) # Do not sent ridiculous short headers if maxlength < 10: - raise TracError, "Header length is too short" + raise TracError, u"Erreur interne: En-tête trop court" try: tmp = name.encode('ascii') header = Header(tmp, 'ascii', maxlinelen=maxlength) @@ -280,7 +280,8 @@ if self._use_tls: self.server.ehlo() if not self.server.esmtp_features.has_key('starttls'): - raise TracError, "TLS enabled but server does not support TLS" + raise TracError, u"TLS activé mais le server ne supporte " \ + u"pas les communications sécurisées TLS" self.server.starttls() self.server.ehlo() if self.user_name: @@ -330,7 +331,7 @@ (ccaddrs, recipients) = remove_dup(ccaddrs, recipients) (accaddrs, recipients) = remove_dup(accaddrs, recipients) (bccaddrs, recipients) = remove_dup(bccaddrs, recipients) - + # if there is not valid recipient, leave immediately if len(recipients) < 1: self.env.log.info('no recipient for a ticket notification') @@ -349,8 +350,8 @@ try: dummy = body.encode('ascii') except UnicodeDecodeError: - raise TracError, "Ticket contains non-Ascii chars. " \ - "Please change encoding setting" + raise TracError, u"Le ticket contient des caractères non Ascii" \ + u"Veuillez changer les paramètres d'encodage" msg = MIMEText(body, 'plain') # Message class computes the wrong type from MIMEText constructor, # which does not take a Charset object as initializer. Reset the diff --exclude=.svn -Naur trac-0.10.4/trac/perm.py trac-0.10.4-PKG/trac/perm.py --- trac-0.10.4/trac/perm.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/perm.py 2007-08-24 11:09:40.000000000 +0200 @@ -32,7 +32,7 @@ self.action = action def __str__ (self): - return '%s privileges are required to perform this operation' % self.action + return u'Les privilèges %s sont nécessaires pour exécuter cette opération' % self.action class IPermissionRequestor(Interface): @@ -40,7 +40,7 @@ def get_permission_actions(): """Return a list of actions defined by this component. - + The items in the list may either be simple strings, or `(string, sequence)` tuples. The latter are considered to be "meta permissions" that group several simple actions under one name for @@ -54,7 +54,7 @@ def get_user_permissions(username): """Return all permissions for the user with the specified name. - + The permissions are returned as a dictionary where the key is the name of the permission, and the value is either `True` for granted permissions or `False` for explicitly denied permissions.""" @@ -84,7 +84,7 @@ class DefaultPermissionStore(Component): """Default implementation of permission storage and simple group management. - + This component uses the `PERMISSION` table in the database to store both permissions and groups. """ @@ -95,7 +95,7 @@ def get_user_permissions(self, username): """Retrieve the permissions for the given user and return them in a dictionary. - + The permissions are stored in the database as (username, action) records. There's simple support for groups by using lowercase names for the action column: such a record represents a group and not an actual @@ -185,7 +185,7 @@ """Grant the user with the given name permission to perform to specified action.""" if action.isupper() and action not in self.get_actions(): - raise TracError, '%s is not a valid action.' % action + raise TracError, u"%s n'est pas une action valide" % action self.store.grant_permission(username, action) @@ -205,7 +205,7 @@ def get_user_permissions(self, username=None): """Return the permissions of the specified user. - + The return value is a dictionary containing all the actions as keys, and a boolean value. `True` means that the permission is granted, `False` means the permission is denied.""" diff --exclude=.svn -Naur trac-0.10.4/trac/scripts/admin.py trac-0.10.4-PKG/trac/scripts/admin.py --- trac-0.10.4/trac/scripts/admin.py 2007-10-19 14:48:30.000000000 +0200 +++ trac-0.10.4-PKG/trac/scripts/admin.py 2007-08-24 11:10:28.000000000 +0200 @@ -1200,7 +1200,7 @@ arg = content.split(' ', 1)[0] doc = getattr(TracAdmin, '_help_' + arg) except AttributeError: - raise TracError('Unknown trac-admin command "%s"' % content) + raise TracError(u'Commande trac-admin inconnue "%s"' % content) if arg != content: for cmd, help in doc: if cmd.startswith(content): diff --exclude=.svn -Naur trac-0.10.4/trac/Search.py trac-0.10.4-PKG/trac/Search.py --- trac-0.10.4/trac/Search.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/Search.py 2007-08-24 11:12:06.000000000 +0200 @@ -74,7 +74,7 @@ parameters. The result is returned as a (string, params) tuple. """ if len(columns) < 1 or len(terms) < 1: - raise TracError('Empty search attempt, this should really not happen.') + raise TracError(u'Tentative de recherche vide: ceci ne devrait pas arriver.') likes = ['%s %s' % (i, db.like()) for i in columns] c = ' OR '.join(likes) @@ -109,7 +109,7 @@ if beg < len(text)-maxlen: msg = msg + ' ...' return msg - + class SearchModule(Component): @@ -117,7 +117,7 @@ IWikiSyntaxProvider) search_sources = ExtensionPoint(ISearchSource) - + RESULTS_PER_PAGE = 10 min_query_length = IntOption('search', 'min_query_length', 3, @@ -132,7 +132,7 @@ if not req.perm.has_permission('SEARCH_VIEW'): return yield ('mainnav', 'search', - html.A('Search', href=req.href.search(), accesskey=4)) + html.A(u'Rechercher', href=req.href.search(), accesskey=4)) # IPermissionRequestor methods @@ -150,19 +150,19 @@ available_filters = [] for source in self.search_sources: available_filters += source.get_search_filters(req) - + filters = [f[0] for f in available_filters if req.args.has_key(f[0])] if not filters: filters = [f[0] for f in available_filters if len(f) < 3 or len(f) > 2 and f[2]] - + req.hdf['search.filters'] = [ { 'name': filter[0], 'label': filter[1], 'active': filter[0] in filters } for filter in available_filters] - - req.hdf['title'] = 'Search' + + req.hdf['title'] = u'Recherche' query = req.args.get('q') if query: @@ -173,9 +173,10 @@ terms = search_terms(query) # Refuse queries that obviously would result in a huge result set if len(terms) == 1 and len(terms[0]) < self.min_query_length: - raise TracError('Search query too short. ' - 'Query must be at least %d characters long.' % \ - self.min_query_length, 'Search Error') + raise TracError(u'La requête de recherche est trop courte. ' + u'La requête doit contenir au moins %d ' + u'caractères.' % self.min_query_length, + u'Erreur de recherche') results = [] for source in self.search_sources: results += list(source.get_search_results(req, terms, filters)) @@ -185,7 +186,7 @@ n_pages = (n-1) / page_size + 1 results = results[(page-1) * page_size: page * page_size] - req.hdf['title'] = 'Search Results' + req.hdf['title'] = u'Résultats de la recherche' req.hdf['search.q'] = req.args.get('q') req.hdf['search.page'] = page req.hdf['search.n_hits'] = n @@ -195,12 +196,12 @@ next_href = req.href.search(zip(filters, ['on'] * len(filters)), q=req.args.get('q'), page=page + 1, noquickjump=1) - add_link(req, 'next', next_href, 'Next Page') + add_link(req, 'next', next_href, u'Page suivante') if page > 1: prev_href = req.href.search(zip(filters, ['on'] * len(filters)), q=req.args.get('q'), page=page - 1, noquickjump=1) - add_link(req, 'prev', prev_href, 'Previous Page') + add_link(req, 'prev', prev_href, u'Page précédente') req.hdf['search.page_href'] = req.href.search( zip(filters, ['on'] * len(filters)), q=req.args.get('q'), noquickjump=1) @@ -222,7 +223,7 @@ if kwd[0] == '/': quickjump_href = req.href.browser(kwd) name = kwd - description = 'Browse repository path ' + kwd + description = u'Naviguer dans le chemin du dépôt ' + kwd else: link = wiki_to_link(kwd, self.env, req) if isinstance(link, Element): @@ -240,10 +241,10 @@ req.redirect(quickjump_href) # IWikiSyntaxProvider methods - + def get_wiki_syntax(self): return [] - + def get_link_resolvers(self): yield ('search', self._format_link) diff --exclude=.svn -Naur trac-0.10.4/trac/Settings.py trac-0.10.4-PKG/trac/Settings.py --- trac-0.10.4/trac/Settings.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/Settings.py 2007-08-24 11:12:43.000000000 +0200 @@ -33,7 +33,7 @@ def get_navigation_items(self, req): yield ('metanav', 'settings', - html.A('Settings', href=req.href.settings())) + html.A(u'Réglages', href=req.href.settings())) # IRequestHandler methods @@ -49,7 +49,7 @@ elif action == 'load': self._do_load(req) - req.hdf['title'] = 'Settings' + req.hdf['title'] = u'Paramétrage' req.hdf['settings'] = req.session if req.authname == 'anonymous': req.hdf['settings.session_id'] = req.session.sid diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/api.py trac-0.10.4-PKG/trac/ticket/api.py --- trac-0.10.4/trac/ticket/api.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/api.py 2007-08-24 11:15:59.000000000 +0200 @@ -21,7 +21,7 @@ from trac.perm import IPermissionRequestor, PermissionSystem from trac.Search import ISearchSource, search_to_sql, shorten_result from trac.util.html import html, Markup -from trac.util.text import shorten_line +from trac.util.text import shorten_line, translate from trac.wiki import IWikiSyntaxProvider, Formatter @@ -34,7 +34,7 @@ def ticket_changed(ticket, comment, author, old_values): """Called when a ticket is modified. - + `old_values` is a dictionary containing the previous values of the fields that have changed. """ @@ -52,7 +52,7 @@ def validate_ticket(req, ticket): """Validate a ticket after it's been populated from user input. - + Must return a list of `(field, message)` tuples, one for each problem detected. `field` can be `None` to indicate an overall problem with the ticket. Therefore, a return value of `[]` means everything is OK.""" @@ -96,7 +96,7 @@ fields.append(field) # Owner field, can be text or drop-down depending on configuration - field = {'name': 'owner', 'label': 'Owner'} + field = {'name': 'owner', 'label': 'Propriétaire'} if self.restrict_owner: field['type'] = 'select' users = [] @@ -125,7 +125,9 @@ # Fields without possible values are treated as if they didn't # exist continue - field = {'name': name, 'type': 'select', 'label': name.title(), + # de Trac 0.10.4: field = {'name': name, 'type': 'select', 'label': name.title(), + field = {'name': name, 'type': 'select', + 'label': translate(self.env, name, True), 'value': self.config.get('ticket', 'default_' + name), 'options': options} if name in ('status', 'resolution'): @@ -137,7 +139,9 @@ # Advanced text fields for name in ('keywords', 'cc', ): - field = {'name': name, 'type': 'text', 'label': name.title()} + # de Trac 0.10.4: field = {'name': name, 'type': 'text', 'label': name.title()} + field = {'name': name, 'type': 'text', + 'label': translate(self.env, name, True)} fields.append(field) for field in self.get_custom_fields(): @@ -184,8 +188,8 @@ def get_permission_actions(self): return ['TICKET_APPEND', 'TICKET_CREATE', 'TICKET_CHGPROP', 'TICKET_VIEW', - ('TICKET_MODIFY', ['TICKET_APPEND', 'TICKET_CHGPROP']), - ('TICKET_ADMIN', ['TICKET_CREATE', 'TICKET_MODIFY', + ('TICKET_MODIFY', ['TICKET_APPEND', 'TICKET_CHGPROP']), + ('TICKET_ADMIN', ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW'])] # IWikiSyntaxProvider methods @@ -244,10 +248,10 @@ cnum = target if href: return html.A(label, href="%s#comment:%s" % (href, cnum), - title="Comment %s for %s:%s" % (cnum, type, id)) + title= u"Commentaire %s pour %s:%s" % (cnum, type, id)) else: return label - + # ISearchSource methods def get_search_filters(self, req): diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/model.py trac-0.10.4-PKG/trac/ticket/model.py --- trac-0.10.4/trac/ticket/model.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/model.py 2007-08-24 11:20:44.000000000 +0200 @@ -25,6 +25,7 @@ from trac.core import TracError from trac.ticket import TicketSystem from trac.util import sorted, embedded_numbers +from trac.util.text import translate __all__ = ['Ticket', 'Type', 'Status', 'Resolution', 'Priority', 'Severity', 'Component', 'Milestone', 'Version'] @@ -83,8 +84,8 @@ % ','.join(std_fields), (tkt_id,)) row = cursor.fetchone() if not row: - raise TracError('Ticket %d does not exist.' % tkt_id, - 'Invalid Ticket Number') + raise TracError(u'Le ticket %d n\'existe pas.' % tkt_id, + u'Numéro de ticket invalide') self.id = tkt_id for i in range(len(std_fields)): @@ -131,7 +132,7 @@ def insert(self, when=0, db=None): """Add ticket to database""" - assert not self.exists, 'Cannot insert an existing ticket' + assert not self.exists, u'Impossible d\'insérer un ticket existant' db, handle_ta = self._get_db_for_write(db) # Add a timestamp @@ -187,7 +188,7 @@ the database. Returns False if there were no changes to save, True otherwise. """ - assert self.exists, 'Cannot update a new ticket' + assert self.exists, u'Impossible de mettre à jour un nouveau ticket' if not self._old and not comment: return False # Not modified @@ -225,7 +226,7 @@ custom_fields = [f['name'] for f in self.fields if f.get('custom')] for name in self._old.keys(): if name in custom_fields: - cursor.execute("SELECT * FROM ticket_custom " + cursor.execute("SELECT * FROM ticket_custom " "WHERE ticket=%s and name=%s", (self.id, name)) if cursor.fetchone(): cursor.execute("UPDATE ticket_custom SET value=%s " @@ -331,7 +332,7 @@ (self.type, name)) row = cursor.fetchone() if not row: - raise TracError, '%s %s does not exist.' % (self.type, name) + raise TracError, '%s %s n\'existe pas.' % (self.type, name) self.value = self._old_value = row[0] self.name = self._old_name = name else: @@ -341,7 +342,7 @@ exists = property(fget=lambda self: self._old_value is not None) def delete(self, db=None): - assert self.exists, 'Cannot deleting non-existent %s' % self.type + assert self.exists, u'Impossible d\'effacer %s (inexistant)' % self.type if not db: db = self.env.get_db_cnx() handle_ta = True @@ -359,8 +360,8 @@ self.name = self._old_name = None def insert(self, db=None): - assert not self.exists, 'Cannot insert existing %s' % self.type - assert self.name, 'Cannot create %s with no name' % self.type + assert not self.exists, u"Impossible d'ajouter %s (existe déja)" % self.type + assert self.name, u"Impossible de créer %s (anonyme)" % self.type self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -384,8 +385,8 @@ self._old_value = self.value def update(self, db=None): - assert self.exists, 'Cannot update non-existent %s' % self.type - assert self.name, 'Cannot update %s with no name' % self.type + assert self.exists, u'Impossible de mettre à jour %s (inexistant)' % self.type + assert self.name, u'Impossible de mettre à jour %s (anonyme)' % self.type self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -457,7 +458,7 @@ "WHERE name=%s", (name,)) row = cursor.fetchone() if not row: - raise TracError, 'Component %s does not exist.' % name + raise TracError, u'Le composant %s n\'existe pas' % name self.name = self._old_name = name self.owner = row[0] or None self.description = row[1] or '' @@ -469,7 +470,7 @@ exists = property(fget=lambda self: self._old_name is not None) def delete(self, db=None): - assert self.exists, 'Cannot deleting non-existent component' + assert self.exists, u'Impossible de supprimer un composant inexistant' if not db: db = self.env.get_db_cnx() handle_ta = True @@ -486,8 +487,8 @@ db.commit() def insert(self, db=None): - assert not self.exists, 'Cannot insert existing component' - assert self.name, 'Cannot create component with no name' + assert not self.exists, u"Impossible d'ajouter un composant déjà existant" + assert self.name, u'Impossible de créer un composant sans nom' self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -505,8 +506,8 @@ db.commit() def update(self, db=None): - assert self.exists, 'Cannot update non-existent component' - assert self.name, 'Cannot update component with no name' + assert self.exists, u'Impossible de mettre à jour un composant inexistant' + assert self.name, u'Impossible de mettre à jour un composant anonyme' self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -564,8 +565,8 @@ "FROM milestone WHERE name=%s", (name,)) row = cursor.fetchone() if not row: - raise TracError('Milestone %s does not exist.' % name, - 'Invalid Milestone Name') + raise TracError(u'%s %s n\'existe pas.' % ( translate(self.env,'The_milestone',True), name), + u'Nom de %s invalide' % translate(self.env,'milestone')) self.name = row[0] self.due = row[1] and int(row[1]) or 0 self.completed = row[2] and int(row[2]) or 0 @@ -594,14 +595,14 @@ for tkt_id in tkt_ids: ticket = Ticket(self.env, tkt_id, db) ticket['milestone'] = retarget_to - ticket.save_changes(author, 'Milestone %s deleted' % self.name, + ticket.save_changes(author, u'%s %s effacé' % (translate(self.env,'Milestone',True), self.name), now, db=db) if handle_ta: db.commit() def insert(self, db=None): - assert self.name, 'Cannot create milestone with no name' + assert self.name, u'Impossible de créer un %s sans nom' % translate(self.env,'milestone') self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -619,7 +620,7 @@ db.commit() def update(self, db=None): - assert self.name, 'Cannot update milestone with no name' + assert self.name, u'Impossible de mettre à jour un %s sans nom' % translate(self.env,'milestone') self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -678,7 +679,7 @@ "WHERE name=%s", (name,)) row = cursor.fetchone() if not row: - raise TracError, 'Version %s does not exist.' % name + raise TracError, u"La version %s n'existe pas." % name self.name = self._old_name = name self.time = row[0] and int(row[0]) or None self.description = row[1] or '' @@ -690,7 +691,7 @@ exists = property(fget=lambda self: self._old_name is not None) def delete(self, db=None): - assert self.exists, 'Cannot deleting non-existent version' + assert self.exists, u'Impossible de supprimer une version inexistante' if not db: db = self.env.get_db_cnx() handle_ta = True @@ -707,8 +708,8 @@ db.commit() def insert(self, db=None): - assert not self.exists, 'Cannot insert existing version' - assert self.name, 'Cannot create version with no name' + assert not self.exists, u"Impossible d'ajouter une version déjà existante" + assert self.name, u'Impossible de créer une version anonyme' self.name = self.name.strip() if not db: db = self.env.get_db_cnx() @@ -726,8 +727,8 @@ db.commit() def update(self, db=None): - assert self.exists, 'Cannot update non-existent version' - assert self.name, 'Cannot update version with no name' + assert self.exists, u'Impossible de mettre à jour une version inexistante' + assert self.name, u'Impossible de mettre à jour une version anonyme' self.name = self.name.strip() if not db: db = self.env.get_db_cnx() diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/query.py trac-0.10.4-PKG/trac/ticket/query.py --- trac-0.10.4/trac/ticket/query.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/query.py 2007-08-24 11:22:31.000000000 +0200 @@ -67,11 +67,11 @@ for filter in filters: filter = filter.split('=') if len(filter) != 2: - raise QuerySyntaxError, 'Query filter requires field and ' \ - 'constraints separated by a "="' + raise QuerySyntaxError, u'Le filtre de requête impose que les champs et les ' \ + u'contraintes soient séparés par un "="' field,values = filter if not field: - raise QuerySyntaxError, 'Query filter requires field name' + raise QuerySyntaxError, u'Le filtre de requête a besoin d\'un nom de champ' values = values.split('|') mode, neg = '', '' if field[-1] in ('~', '^', '$'): @@ -164,9 +164,9 @@ for i in range(1, len(columns)): name, val = columns[i], row[i] if name == self.group: - val = val or 'None' + val = val or 'Aucun' elif name == 'reporter': - val = val or 'anonymous' + val = val or 'Anonyme' elif name in ['changetime', 'time']: val = int(val) elif val is None: @@ -352,11 +352,11 @@ # IContentConverter methods def get_supported_conversions(self): - yield ('rss', 'RSS Feed', 'xml', + yield ('rss', u'Flux RSS', 'xml', 'trac.ticket.Query', 'application/rss+xml', 8) - yield ('csv', 'Comma-delimited Text', 'csv', + yield ('csv', u'Texte délimité par des virgules', 'csv', 'trac.ticket.Query', 'text/csv', 8) - yield ('tab', 'Tab-delimited Text', 'tsv', + yield ('tab', u'Texte délimité par des tabulations', 'tsv', 'trac.ticket.Query', 'text/tab-separated-values', 8) def convert_content(self, req, mimetype, query, key): @@ -377,7 +377,7 @@ if req.perm.has_permission('TICKET_VIEW') and \ not self.env.is_component_enabled(ReportModule): yield ('mainnav', 'tickets', - html.A('View Tickets', href=req.href.query())) + html.A(u'Voir les tickets', href=req.href.query())) # IRequestHandler methods @@ -485,21 +485,21 @@ def _get_constraint_modes(self): modes = {} modes['text'] = [ - {'name': "contains", 'value': "~"}, - {'name': "doesn't contain", 'value': "!~"}, - {'name': "begins with", 'value': "^"}, - {'name': "ends with", 'value': "$"}, - {'name': "is", 'value': ""}, - {'name': "is not", 'value': "!"} + {'name': u"contient", 'value': "~"}, + {'name': u"ne contient pas", 'value': "!~"}, + {'name': u"débute par", 'value': "^"}, + {'name': u"fini par", 'value': "$"}, + {'name': u"est", 'value': ""}, + {'name': u"n'est pas", 'value': "!"} ] modes['select'] = [ - {'name': "is", 'value': ""}, - {'name': "is not", 'value': "!"} + {'name': u"est", 'value': ""}, + {'name': u"n'est pas", 'value': "!"} ] return modes def display_html(self, req, query): - req.hdf['title'] = 'Custom Query' + req.hdf['title'] = u'Requête personnalisée' add_stylesheet(req, 'common/css/report.css') add_script(req, 'common/js/query.js') @@ -652,10 +652,10 @@ return (req.hdf.render('query_rss.cs'), 'application/rss+xml') # IWikiSyntaxProvider methods - + def get_wiki_syntax(self): return [] - + def get_link_resolvers(self): yield ('query', self._format_link) @@ -673,20 +673,22 @@ class TicketQueryMacro(WikiMacroBase): - """Macro that lists tickets that match certain criteria. + u"""Macro listant les tickets répondant à certains critères. - This macro accepts two parameters, the second of which is optional. + Cette macro accepte deux paramètres, le second étant optionnel. - The first parameter is the query itself, and uses the same syntax as for - `query:` wiki links (but '''not''' the variant syntax starting with "?"). - - The second parameter determines how the list of tickets is presented: - the default presentation is to list the ticket ID next to the summary, - with each ticket on a separate line. - If the second parameter is given, it must be one of: - - '''compact''' -- the tickets are presented as a comma-separated - list of ticket IDs. - - '''count''' -- only the count of matching tickets is displayed + Le premier paramètre est la requête elle-même, et utilise la même syntaxe que + celle des `query:` liens wiki (cependant la syntaxe alternative commençant par + "?" '''n'est pas''' gérée). + + Le second paramètre sélectionne comment la liste des tickets est presentée: + la présentation par défaut est de lister + l'identifiant du ticket juste à coté de son intitulé, chaque ticket étant + affiché sur une ligne distincte. + Si le second paramètre est spécifié, il doit alors correspondre à : + - '''compact''' -- les tickets sont présentés comme une liste + d'identifiants des tickets, séparés par des virgules. + - '''count''' -- seul le nombre de tickets correspondants est affiché. """ def render_macro(self, req, name, content): @@ -717,7 +719,7 @@ return html.SPAN(alist[0], *[(', ', a) for a in alist[1:]]) elif count: cnt = len(tickets) - return html.SPAN(cnt, title='%d tickets for which %s' % + return html.SPAN(cnt, title=u'%d tickets pour chaque %s' % (cnt, query_string)) else: return html.DL([(html.DT(ticket_anchor(ticket)), diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/report.py trac-0.10.4-PKG/trac/ticket/report.py --- trac-0.10.4/trac/ticket/report.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/report.py 2007-10-19 12:48:58.000000000 +0200 @@ -27,7 +27,7 @@ from trac.util.datefmt import format_date, format_time, format_datetime, \ http_date from trac.util.html import html -from trac.util.text import unicode_urlencode +from trac.util.text import to_unicode, unicode_urlencode, translate from trac.web import IRequestHandler from trac.web.chrome import add_link, add_stylesheet, INavigationContributor from trac.wiki import wiki_to_html, IWikiSyntaxProvider, Formatter @@ -46,14 +46,14 @@ if not req.perm.has_permission('REPORT_VIEW'): return yield ('mainnav', 'tickets', - html.A('View Tickets', href=req.href.report())) + html.A(u'Voir les tickets', href=req.href.report())) - # IPermissionRequestor methods + # IPermissionRequestor methods - def get_permission_actions(self): - actions = ['REPORT_CREATE', 'REPORT_DELETE', 'REPORT_MODIFY', - 'REPORT_SQL_VIEW', 'REPORT_VIEW'] - return actions + [('REPORT_ADMIN', actions)] + def get_permission_actions(self): + actions = ['REPORT_CREATE', 'REPORT_DELETE', 'REPORT_MODIFY', + 'REPORT_SQL_VIEW', 'REPORT_VIEW'] + return actions + [('REPORT_ADMIN', actions)] # IRequestHandler methods @@ -93,7 +93,7 @@ return resp if id != -1 or action == 'new': - add_link(req, 'up', req.href.report(), 'Available Reports') + add_link(req, 'up', req.href.report(), u'Rapports disponibles') # Kludge: Reset session vars created by query module so that the # query navigation links on the ticket page don't confuse the user @@ -163,9 +163,9 @@ cursor.execute("SELECT title FROM report WHERE id = %s", (id,)) row = cursor.fetchone() if not row: - raise TracError('Report %s does not exist.' % id, - 'Invalid Report Number') - req.hdf['title'] = 'Delete Report {%s} %s' % (id, row[0]) + raise TracError(u"Le rapport %s n'existe pas." % id, + u'Numéro de rapport invalide') + req.hdf['title'] = u'Supprimer le rapport {%s} %s' % (id, row[0]) req.hdf['report'] = { 'id': id, 'mode': 'delete', @@ -184,21 +184,21 @@ "WHERE id=%s", (id,)) row = cursor.fetchone() if not row: - raise TracError('Report %s does not exist.' % id, - 'Invalid Report Number') + raise TracError(u"Le rapport %s n'existe pas." % id, + u'Numéro de rapport invalide') title = row[0] or '' description = row[1] or '' query = row[2] or '' if copy: - title += ' (copy)' + title += u' (copie)' if copy or id == -1: - req.hdf['title'] = 'Create New Report' + req.hdf['title'] = u'Créer un nouveau rapport' req.hdf['report.href'] = req.href.report() req.hdf['report.action'] = 'new' else: - req.hdf['title'] = 'Edit Report {%d} %s' % (id, title) + req.hdf['title'] = u'Éditer le rapport {%d} %s' % (id, title) req.hdf['report.href'] = req.href.report(id) req.hdf['report.action'] = 'edit' @@ -223,7 +223,7 @@ try: args = self.get_var_args(req) except ValueError,e: - raise TracError, 'Report failed: %s' % e + raise TracError, u'Échec du rapport: %s' % to_unicode(e.message) title, description, sql = self.get_info(db, id, args) @@ -245,7 +245,8 @@ try: cols, rows = self.execute_report(req, db, id, sql, args) except Exception, e: - req.hdf['report.message'] = 'Report execution failed: %s' % e + req.hdf['report.message'] = \ + u"Échec de l'exécution du rapport: %s" % to_unicode(e.message) return 'report.cs', None # Convert the header info to HDF-format @@ -264,7 +265,7 @@ elif title[-1] == '_': title = title[:-1] req.hdf[prefix + '.breakrow'] = 1 - req.hdf[prefix] = title + req.hdf[prefix] = translate(self.env, title, True) idx = idx + 1 if req.args.has_key('sort'): @@ -381,20 +382,20 @@ href = '' if params: href = '&' + unicode_urlencode(params) - add_link(req, 'alternate', '?format=rss' + href, 'RSS Feed', + add_link(req, 'alternate', '?format=rss' + href, u'Flux RSS', 'application/rss+xml', 'rss') add_link(req, 'alternate', '?format=csv' + href, - 'Comma-delimited Text', 'text/plain') + u'Texte délimité par des virgules', 'text/plain') add_link(req, 'alternate', '?format=tab' + href, - 'Tab-delimited Text', 'text/plain') + u'Texte délimité par des tabulations', 'text/plain') if req.perm.has_permission('REPORT_SQL_VIEW'): - add_link(req, 'alternate', '?format=sql', 'SQL Query', + add_link(req, 'alternate', '?format=sql', u'Requête SQL', 'text/plain') def execute_report(self, req, db, id, sql, args): sql, args = self.sql_sub_vars(req, sql, args, db) if not sql: - raise TracError('Report %s has no SQL query.' % id) + raise TracError(u'Le rapport %s ne contient pas de requête SQL.' % id) if sql.find('__group__') == -1: req.hdf['report.sorting.enabled'] = 1 @@ -415,17 +416,17 @@ if id == -1: # If no particular report was requested, display # a list of available reports instead - title = 'Available Reports' + title = u'Rapports disponibles' sql = 'SELECT id AS report, title FROM report ORDER BY report' - description = 'This is a list of reports available.' + description = u'Liste des rapports disponibles' else: cursor = db.cursor() cursor.execute("SELECT title,query,description from report " "WHERE id=%s", (id,)) row = cursor.fetchone() if not row: - raise TracError('Report %d does not exist.' % id, - 'Invalid Report Number') + raise TracError(u"Le rapport %s n'existe pas." % id, + u'Numéro de rapport invalide') title = row[0] or '' sql = row[1] description = row[2] or '' @@ -453,8 +454,7 @@ try: arg = args[aname] except KeyError: - raise TracError("Dynamic variable '$%s' not defined." \ - % aname) + raise TracError(u"La variable dynamique '$%s' n'est pas définie." % aname) req.hdf['report.var.' + aname] = arg values.append(arg) @@ -515,9 +515,9 @@ if description: req.write('-- %s\n\n' % '\n-- '.join(description.splitlines())) req.write(sql) - + # IWikiSyntaxProvider methods - + def get_link_resolvers(self): yield ('report', self._format_link) diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/roadmap.py trac-0.10.4-PKG/trac/ticket/roadmap.py --- trac-0.10.4/trac/ticket/roadmap.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/roadmap.py 2007-08-24 11:45:26.000000000 +0200 @@ -24,7 +24,7 @@ from trac.util.datefmt import format_date, format_datetime, parse_date, \ pretty_timedelta from trac.util.html import html, unescape, Markup -from trac.util.text import shorten_line, CRLF, to_unicode +from trac.util.text import shorten_line, CRLF, to_unicode, translate from trac.ticket import Milestone, Ticket, TicketSystem from trac.Timeline import ITimelineEventProvider from trac.web import IRequestHandler @@ -129,7 +129,7 @@ if not req.perm.has_permission('ROADMAP_VIEW'): return yield ('mainnav', 'roadmap', - html.a('Roadmap', href=req.href.roadmap(), accesskey=3)) + html.a(translate(self.env,'Roadmap',True), href=req.href.roadmap(), accesskey=3)) # IPermissionRequestor methods @@ -143,7 +143,7 @@ def process_request(self, req): req.perm.assert_permission('ROADMAP_VIEW') - req.hdf['title'] = 'Roadmap' + req.hdf['title'] = translate(self.env,'Roadmap',True) showall = req.args.get('show') == 'all' req.hdf['roadmap.showall'] = showall @@ -151,7 +151,7 @@ db = self.env.get_db_cnx() milestones = [milestone_to_hdf(self.env, db, req, m) for m in Milestone.select(self.env, showall, db)] - req.hdf['roadmap.milestones'] = milestones + req.hdf['roadmap.milestones'] = milestones for idx, milestone in enumerate(milestones): milestone_name = unescape(milestone['name']) # Kludge @@ -206,7 +206,7 @@ else: return 'CANCELLED' else: return '' - def escape_value(text): + def escape_value(text): s = ''.join(map(lambda c: (c in ';,\\') and '\\' + c or c, text)) return '\\n'.join(re.split(r'[\r\n]+', s)) @@ -236,7 +236,7 @@ % __version__) write_prop('METHOD', 'PUBLISH') write_prop('X-WR-CALNAME', - self.config.get('project', 'name') + ' - Roadmap') + self.config.get('project', 'name') + ' - ' + translate(self.env,'Roadmap',True)) for milestone in milestones: uid = '<%s/milestone/%s@%s>' % (req.base_path, milestone['name'], host) @@ -306,7 +306,7 @@ def get_timeline_filters(self, req): if req.perm.has_permission('MILESTONE_VIEW'): - yield ('milestone', 'Milestones') + yield ('milestone', translate(self.env,'Milestones',True)) def get_timeline_events(self, req, start, stop, filters): if 'milestone' in filters: @@ -317,7 +317,7 @@ "WHERE completed>=%s AND completed<=%s", (start, stop,)) for completed, name, description in cursor: - title = Markup('Milestone %s completed', name) + title = Markup(translate(self.env,'Milestone',True) + u' %s complété', name) if format == 'rss': href = req.abs_href.milestone(name) message = wiki_to_html(description, self.env, req, db, @@ -340,10 +340,10 @@ def process_request(self, req): milestone_id = req.args.get('id') - + req.perm.assert_permission('MILESTONE_VIEW') - add_link(req, 'up', req.href.roadmap(), 'Roadmap') + add_link(req, 'up', req.href.roadmap(), translate(self.env,'Roadmap',True)) db = self.env.get_db_cnx() milestone = Milestone(self.env, milestone_id, db) @@ -391,23 +391,23 @@ req.perm.assert_permission('MILESTONE_CREATE') if not req.args.has_key('name'): - raise TracError('You must provide a name for the milestone.', - 'Required Field Missing') + raise TracError(u'Vous devez indiquer un nom pour le %s.' % translate(self.env,'milestone',True), + u'Champ requis manquant') due = req.args.get('duedate', '') try: milestone.due = due and parse_date(due) or 0 except ValueError, e: - raise TracError(to_unicode(e), 'Invalid Date Format') + raise TracError(to_unicode(e), 'Format de date non valable') if req.args.has_key('completed'): completed = req.args.get('completeddate', '') try: milestone.completed = completed and parse_date(completed) or 0 except ValueError, e: - raise TracError(to_unicode(e), 'Invalid Date Format') + raise TracError(to_unicode(e), 'Format de date non valable') if milestone.completed > time(): - raise TracError('Completion date may not be in the future', - 'Invalid Completion Date') + raise TracError(u'La date de livraison ne peut pas être dans le futur', + u'Date de livraison non valable') retarget_to = req.args.get('target') if req.args.has_key('retarget'): cursor = db.cursor() @@ -415,7 +415,7 @@ "milestone=%s and status != 'closed'", (retarget_to, milestone.name)) self.env.log.info('Tickets associated with milestone %s ' - 'retargeted to %s' % + 'retargeted to %s' % (milestone.name, retarget_to)) else: milestone.completed = 0 @@ -435,7 +435,7 @@ def _render_confirm(self, req, db, milestone): req.perm.assert_permission('MILESTONE_DELETE') - req.hdf['title'] = 'Milestone %s' % milestone.name + req.hdf['title'] = u'%s %s' % ( translate(self.env,'Milestone',True), milestone.name ) req.hdf['milestone'] = milestone_to_hdf(self.env, db, req, milestone) req.hdf['milestone.mode'] = 'delete' @@ -447,14 +447,14 @@ def _render_editor(self, req, db, milestone): if milestone.exists: req.perm.assert_permission('MILESTONE_MODIFY') - req.hdf['title'] = 'Milestone %s' % milestone.name + req.hdf['title'] = u'%s %s' % ( translate(self.env,'Milestone',True), milestone.name ) req.hdf['milestone.mode'] = 'edit' req.hdf['milestones'] = [m.name for m in Milestone.select(self.env) if m.name != milestone.name] else: req.perm.assert_permission('MILESTONE_CREATE') - req.hdf['title'] = 'New Milestone' + req.hdf['title'] = translate(self.env,'new_Milestone',True) req.hdf['milestone.mode'] = 'new' from trac.util.datefmt import get_date_format_hint, \ @@ -465,7 +465,7 @@ req.hdf['milestone.datetime_now'] = format_datetime() def _render_view(self, req, db, milestone): - req.hdf['title'] = 'Milestone %s' % milestone.name + req.hdf['title'] = u'%s %s' % ( translate(self.env,'Milestone',True), milestone.name ) req.hdf['milestone.mode'] = 'view' req.hdf['milestone'] = milestone_to_hdf(self.env, db, req, milestone) diff --exclude=.svn -Naur trac-0.10.4/trac/ticket/web_ui.py trac-0.10.4-PKG/trac/ticket/web_ui.py --- trac-0.10.4/trac/ticket/web_ui.py 2007-04-20 15:41:46.000000000 +0200 +++ trac-0.10.4-PKG/trac/ticket/web_ui.py 2007-08-24 11:50:49.000000000 +0200 @@ -29,7 +29,7 @@ from trac.util import get_reporter_id from trac.util.datefmt import format_datetime, pretty_timedelta, http_date from trac.util.html import html, Markup -from trac.util.text import CRLF +from trac.util.text import CRLF, translate from trac.web import IRequestHandler from trac.web.chrome import add_link, add_stylesheet, INavigationContributor from trac.wiki import wiki_to_html, wiki_to_oneliner @@ -57,10 +57,10 @@ value = ticket[name] if value: if value not in field['options']: - raise InvalidTicket('"%s" is not a valid value for ' - 'the %s field.' % (value, name)) + raise InvalidTicket(u'"%s" n\'est pas une valeur valide pour ' + u'le champ %s.' % (value, name)) elif not field.get('optional', False): - raise InvalidTicket('field %s must be set' % name) + raise InvalidTicket(u'Le champ %s doit être défini' % name) try: # comment index must be a number @@ -70,16 +70,16 @@ if replyto != 'description': int(replyto or 0) except ValueError: - raise InvalidTicket('Invalid comment threading identifier') + raise InvalidTicket(u'Identifiant de fil de commentaire invalide') # Custom validation rules for manipulator in self.ticket_manipulators: for field, message in manipulator.validate_ticket(req, ticket): if field: - raise InvalidTicket("The ticket %s field is invalid: %s" % + raise InvalidTicket(u"Le champ %s du ticket est invalide: %s" % (field, message)) else: - raise InvalidTicket("Invalid ticket: %s" % message) + raise InvalidTicket(u"Ticket invalide: %s" % message) class NewticketModule(TicketModuleBase): @@ -117,8 +117,8 @@ def get_navigation_items(self, req): if not req.perm.has_permission('TICKET_CREATE'): return - yield ('mainnav', 'newticket', - html.A('New Ticket', href=req.href.newticket(), accesskey=7)) + yield ('mainnav', 'newticket', + html.A(u'Nouveau ticket', href=req.href.newticket(), accesskey=7)) # IRequestHandler methods @@ -145,7 +145,7 @@ description = wiki_to_html(ticket['description'], self.env, req, db) req.hdf['newticket.description_preview'] = description - req.hdf['title'] = 'New Ticket' + req.hdf['title'] = u'Nouveau ticket' req.hdf['newticket'] = ticket.values field_names = [field['name'] for field in ticket.fields @@ -167,7 +167,7 @@ 'resolution'): field['skip'] = True elif name == 'owner': - field['label'] = 'Assign to' + field['label'] = u'Assigner à' if not req.perm.has_permission('TICKET_MODIFY'): field['skip'] = True elif name == 'milestone': @@ -178,6 +178,7 @@ if milestone.is_completed: options.remove(option) field['options'] = options + field['label'] = translate(self.env, field['label']) req.hdf['newticket.fields.' + name] = field if req.perm.has_permission('TICKET_APPEND'): @@ -191,7 +192,7 @@ def _do_create(self, req, db): if not req.args.get('summary'): - raise TracError('Tickets must contain a summary.') + raise TracError(u'Les tickets doivent contenir un intitulé.') ticket = Ticket(self.env, db=db) ticket.populate(req.args) @@ -206,8 +207,8 @@ tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) except Exception, e: - self.log.exception("Failure sending notification on creation of " - "ticket #%s: %s" % (ticket.id, e)) + self.log.exception(u"Impossible d'envoyer une notification sur la création du " + u"ticket #%s: %s" % (ticket.id, e)) # Redirect the user to the newly created ticket if req.args.get('attachment'): @@ -243,11 +244,11 @@ # IContentConverter methods def get_supported_conversions(self): - yield ('csv', 'Comma-delimited Text', 'csv', + yield ('csv', u'Texte délimité par des virgules', 'csv', 'trac.ticket.Ticket', 'text/csv', 8) - yield ('tab', 'Tab-delimited Text', 'tsv', + yield ('tab', u'Texte délimité par des tabulations', 'tsv', 'trac.ticket.Ticket', 'text/tab-separated-values', 8) - yield ('rss', 'RSS Feed', 'xml', + yield ('rss', u'Flux RSS', 'xml', 'trac.ticket.Ticket', 'application/rss+xml', 8) def convert_content(self, req, mimetype, ticket, key): @@ -326,14 +327,14 @@ idx = tickets.index(str(ticket.id)) if idx > 0: add_link(req, 'first', req.href.ticket(tickets[0]), - 'Ticket #%s' % tickets[0]) + u'Ticket #%s' % tickets[0]) add_link(req, 'prev', req.href.ticket(tickets[idx - 1]), - 'Ticket #%s' % tickets[idx - 1]) + u'Ticket #%s' % tickets[idx - 1]) if idx < len(tickets) - 1: add_link(req, 'next', req.href.ticket(tickets[idx + 1]), - 'Ticket #%s' % tickets[idx + 1]) + u'Ticket #%s' % tickets[idx + 1]) add_link(req, 'last', req.href.ticket(tickets[-1]), - 'Ticket #%s' % tickets[-1]) + u'Ticket #%s' % tickets[-1]) add_link(req, 'up', req.session['query_href']) add_stylesheet(req, 'common/css/ticket.css') @@ -350,17 +351,17 @@ def get_timeline_filters(self, req): if req.perm.has_permission('TICKET_VIEW'): - yield ('ticket', 'Ticket changes') + yield ('ticket', u'Modification du ticket') if self.timeline_details: - yield ('ticket_details', 'Ticket details', False) + yield ('ticket_details', u'Détails du ticket', False) def get_timeline_events(self, req, start, stop, filters): format = req.args.get('format') - status_map = {'new': ('newticket', 'created'), - 'reopened': ('newticket', 'reopened'), - 'closed': ('closedticket', 'closed'), - 'edit': ('editedticket', 'updated')} + status_map = {'new': ('newticket', u'créé'), + 'reopened': ('newticket', u'réouvert'), + 'closed': ('closedticket', u'fermé'), + 'edit': ('editedticket', u'mis à jour')} href = format == 'rss' and req.abs_href or req.href @@ -368,10 +369,10 @@ comment, cid): if status == 'edit': if 'ticket_details' in filters: - info = '' + info = u'' if len(fields) > 0: - info = ', '.join(['%s' % f for f in \ - fields.keys()]) + ' changed
    ' + info = u', '.join([u'%s' % f for f in \ + fields.keys()]) + u' modifié
    ' else: return None elif 'ticket' in filters: @@ -385,16 +386,16 @@ return None kind, verb = status_map[status] if format == 'rss': - title = 'Ticket #%s (%s %s): %s' % \ - (id, type.lower(), verb, summary) + title = u'Ticket #%s (%s %s): %s' % \ + (id, translate(self.env, type).lower(), verb, summary) else: - title = Markup('Ticket #%s (%s) %s by %s', - summary, id, type, verb, author) + title = Markup(u'Ticket #%s (%s) %s par %s', + summary, id, translate(self.env, type), verb, author) ticket_href = href.ticket(id) if cid: ticket_href += '#comment:' + cid if status == 'new': - message = summary + message = unicode(summary) else: message = Markup(info) if comment: @@ -439,7 +440,7 @@ ev = produce(previous_update, status, fields, comment, cid) if ev: yield ev - + # New tickets if 'ticket' in filters: cursor.execute("SELECT id,time,reporter,type,summary" @@ -470,7 +471,7 @@ .replace('\n', '\\n').replace('\r', '\\r') for f in ticket.fields]) + CRLF) return (content.getvalue(), '%s;charset=utf-8' % mimetype) - + def export_rss(self, req, ticket): db = self.env.get_db_cnx() changes = [] @@ -509,7 +510,7 @@ if req.perm.has_permission('TICKET_CHGPROP'): # TICKET_CHGPROP gives permission to edit the ticket if not req.args.get('summary'): - raise TracError('Tickets must contain summary.') + raise TracError(u'Les tickets doivent contenir un intitulé.') if req.args.has_key('description') or req.args.has_key('reporter'): req.perm.assert_permission('TICKET_ADMIN') @@ -520,15 +521,15 @@ # Mid air collision? if int(req.args.get('ts')) != ticket.time_changed: - raise TracError("Sorry, can not save your changes. " - "This ticket has been modified by someone else " - "since you started", 'Mid Air Collision') + raise TracError(u"Désolé, impossible d'enregistrer vos modifications. " + u"Ce ticket a été modifié par quelqu'un d'autre " + u"depuis que vous avez commencé", u'Collision en plein vol') # Do any action on the ticket? action = req.args.get('action') actions = TicketSystem(self.env).get_available_actions(ticket, req.perm) if action not in actions: - raise TracError('Invalid action') + raise TracError(u'Action invalide') # TODO: this should not be hard-coded like this if action == 'accept': @@ -547,7 +548,7 @@ self._validate_ticket(req, ticket) now = int(time.time()) - cnum = req.args.get('cnum') + cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: # record parent.child relationship @@ -579,7 +580,7 @@ } # -- Ticket fields - + for field in TicketSystem(self.env).get_ticket_fields(): if field['type'] in ('radio', 'select'): value = ticket.values.get(field['name']) @@ -617,8 +618,8 @@ def quote_original(author, original, link): if not 'comment' in req.args: # i.e. the comment was not yet edited req.hdf['ticket.comment'] = '\n'.join( - ['Replying to [%s %s]:' % (link, author)] + - ['> %s' % line for line in original.splitlines()] + ['']) + [u'En réponse à [%s %s]:' % (link, author)] + + [u'> %s' % line for line in original.splitlines()] + ['']) if replyto == 'description': quote_original(ticket['reporter'], ticket['description'], @@ -647,7 +648,7 @@ change['fields']['description'] = '' description_lastmod = change['date'] description_author = change['author'] - + req.hdf['ticket'] = { 'changes': changes, 'replies': replies, diff --exclude=.svn -Naur trac-0.10.4/trac/Timeline.py trac-0.10.4-PKG/trac/Timeline.py --- trac-0.10.4/trac/Timeline.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/Timeline.py 2007-08-24 11:51:46.000000000 +0200 @@ -37,7 +37,7 @@ def get_timeline_filters(self, req): """Return a list of filters that this event provider supports. - + Each filter must be a (name, label) tuple, where `name` is the internal name, and `label` is a human-readable name for display. @@ -49,7 +49,7 @@ def get_timeline_events(self, req, start, stop, filters): """Return a list of events in the time range given by the `start` and `stop` parameters. - + The `filters` parameters is a list of the enabled filters, each item being the name of the tuples returned by `get_timeline_filters`. @@ -77,7 +77,7 @@ if not req.perm.has_permission('TIMELINE_VIEW'): return yield ('mainnav', 'timeline', - html.A('Timeline', href=req.href.timeline(), accesskey=2)) + html.A(u'Historique', href=req.href.timeline(), accesskey=2)) # IPermissionRequestor methods @@ -151,7 +151,7 @@ if maxrows and len(events) > maxrows: del events[maxrows:] - req.hdf['title'] = 'Timeline' + req.hdf['title'] = u'Historique' # Get the email addresses of all known users email_map = {} @@ -192,7 +192,7 @@ add_stylesheet(req, 'common/css/timeline.css') rss_href = req.href.timeline([(f, 'on') for f in filters], daysback=90, max=50, format='rss') - add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', + add_link(req, 'alternate', rss_href, u'Flux RSS', 'application/rss+xml', 'rss') for idx,fltr in enumerate(available_filters): req.hdf['timeline.filters.%d' % idx] = {'name': fltr[0], @@ -216,8 +216,9 @@ 'daysback')] href = req.href.timeline(args+[(f, 'on') for f in other_filters]) raise TracError(Markup( - '%s event provider (%s) failed:

    ' - '%s: %s' - '

    You may want to see the other kind of events from the ' - 'Timeline

    ', + u'Le gestionnaire d\'évènements %s (%s) a echoué:' + u'

    %s: %s' + u'

    Vous voulez probablement consulter les ' + u'autres types d\'évènements de l\'' + u'Historique

    ', ", ".join(guilty_kinds), ep_name, exc_name, to_unicode(exc), href)) diff --exclude=.svn -Naur trac-0.10.4/trac/util/datefmt.py trac-0.10.4-PKG/trac/util/datefmt.py --- trac-0.10.4/trac/util/datefmt.py 2007-04-20 15:41:50.000000000 +0200 +++ trac-0.10.4-PKG/trac/util/datefmt.py 2007-08-24 11:52:41.000000000 +0200 @@ -30,17 +30,17 @@ if not time2: time2 = time.time() if time1 > time2: time2, time1 = time1, time2 - units = ((3600 * 24 * 365, 'year', 'years'), - (3600 * 24 * 30, 'month', 'months'), - (3600 * 24 * 7, 'week', 'weeks'), - (3600 * 24, 'day', 'days'), - (3600, 'hour', 'hours'), - (60, 'minute', 'minutes')) + units = ((3600 * 24 * 365, u'an', u'ans'), + (3600 * 24 * 30, u'mois', u'mois'), + (3600 * 24 * 7, u'semaine', u'semaines'), + (3600 * 24, u'jour', u'jours'), + (3600, u'heure', u'heures'), + (60, u'minute', u'minutes')) age_s = int(time2 - time1) if resolution and age_s < resolution: return '' if age_s < 60: - return '%i second%s' % (age_s, age_s != 1 and 's' or '') + return u'%i seconde%s' % (age_s, age_s != 1 and 's' or '') for u, unit, unit_plural in units: r = float(age_s) / float(u) if r >= 0.9: @@ -111,5 +111,5 @@ except ValueError: continue if seconds == None: - raise ValueError, '%s is not a known date format.' % text + raise ValueError, u'%s n\'est pas un format de date connu.' % text return seconds diff --exclude=.svn -Naur trac-0.10.4/trac/util/__init__.py trac-0.10.4-PKG/trac/util/__init__.py --- trac-0.10.4/trac/util/__init__.py 2007-04-20 15:41:50.000000000 +0200 +++ trac-0.10.4-PKG/trac/util/__init__.py 2007-08-24 11:54:57.000000000 +0200 @@ -30,7 +30,7 @@ from trac.core import TracError from trac.util.html import escape, unescape, Markup, Deuglifier from trac.util.text import CRLF, to_utf8, to_unicode, shorten_line, \ - wrap, pretty_size + wrap, pretty_size, translate from trac.util.datefmt import pretty_timedelta, format_datetime, \ format_date, format_time, \ get_date_format_hint, \ @@ -60,7 +60,7 @@ except NameError: def reversed(x): if hasattr(x, 'keys'): - raise ValueError('mappings do not support reverse iteration') + raise ValueError(u'les dictionnaires ne supportent pas l\'itération inversée') i = len(x) while i > 0: i -= 1 @@ -109,7 +109,7 @@ idx += 1 # A sanity check if idx > 100: - raise Exception('Failed to create unique name: ' + path) + raise Exception(u'Impossible de créer le nom de fichier unique : ' + path) path = '%s.%d%s' % (parts[0], idx, parts[1]) @@ -119,7 +119,7 @@ The optional `input`, which must be a `str` object, is first written to a temporary file from which the process will read. - + (`capturestderr` may not work under Windows 9x.) Example: print Popen3('grep spam','\n\nhere spam\n\n').out @@ -166,10 +166,10 @@ def safe__import__(module_name): """ Safe imports: rollback after a failed import. - + Initially inspired from the RollbackImporter in PyUnit, but it's now much simpler and works better for our needs. - + See http://pyunit.sourceforge.net/notes/reloading.html """ already_imported = sys.modules.copy() diff --exclude=.svn -Naur trac-0.10.4/trac/util/text.py trac-0.10.4-PKG/trac/util/text.py --- trac-0.10.4/trac/util/text.py 2007-04-20 15:41:50.000000000 +0200 +++ trac-0.10.4-PKG/trac/util/text.py 2007-08-24 11:53:39.000000000 +0200 @@ -69,7 +69,7 @@ def unicode_unquote(value): """A unicode aware version of urllib.unquote. - + Take `str` value previously obtained by `unicode_quote`. """ return unquote(value).decode('utf-8') @@ -143,12 +143,20 @@ jump = 512 if size < jump: - return '%d bytes' % size + return u'%d octets' % size - units = ['kB', 'MB', 'GB', 'TB'] + units = [u'ko', u'Mo', u'Go', u'To'] i = 0 while size >= jump and i < len(units): i += 1 size /= 1024. return '%.1f %s' % (size, units[i - 1]) + +# -- Translation + +def translate(env, name, capitalize=False): + if capitalize: + return env.translations.get(name.lower().capitalize(), name.capitalize()) + else: + return env.translations.get(name.lower(), name) diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/api.py trac-0.10.4-PKG/trac/versioncontrol/api.py --- trac-0.10.4/trac/versioncontrol/api.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/api.py 2007-08-24 11:57:09.000000000 +0200 @@ -35,7 +35,7 @@ Yields `(repotype, priority)` pairs, where `repotype` is used to match against the configured `[trac] repository_type` value in TracIni. - + If multiple provider match a given type, the `priority` is used to choose between them (highest number is highest priority). """ @@ -68,7 +68,7 @@ # IRequestFilter methods def pre_process_request(self, req, handler): - from trac.web.chrome import Chrome + from trac.web.chrome import Chrome if handler is not Chrome(self.env): self.get_repository(req.authname).sync() return handler @@ -88,9 +88,9 @@ continue heappush(candidates, (-prio, connector)) if not candidates: - raise TracError('Unsupported version control system "%s". ' - 'Check that the Python bindings for "%s" are ' - 'correctly installed.' % + raise TracError(u'Système de contrôle de version "%s" non supporté. ' + u'Contrôlez que les librairies Python pour "%s" sont ' + u'correctement installées.' % ((self.repository_type,)*2)) self._connector = heappop(candidates)[1] db = self.env.get_db_cnx() # prevent possible deadlock, see #4465 @@ -119,11 +119,12 @@ class NoSuchChangeset(TracError): def __init__(self, rev): - TracError.__init__(self, "No changeset %s in the repository" % rev) + TracError.__init__(self, u"Aucune version %s n'est répertoriée dans le dépôt" \ + % rev) class NoSuchNode(TracError): def __init__(self, path, rev, msg=None): - TracError.__init__(self, "%sNo node %s at revision %s" \ + TracError.__init__(self, u"%sLe chemin %s n'existe pas en révision %s" \ % (msg and '%s: ' % msg or '', path, rev)) class Repository(object): @@ -148,10 +149,10 @@ def sync(self, rev_callback=None): """Perform a sync of the repository cache, if relevant. - + If given, `rev_callback` must be a callable taking a `rev` parameter. The backend will call this function for each `rev` it decided to - synchronize, once the synchronization changes are committed to the + synchronize, once the synchronization changes are committed to the cache. """ pass @@ -186,8 +187,8 @@ self.get_node(path, rev) return True except TracError: - return False - + return False + def get_node(self, path, rev=None): """Retrieve a Node from the repository at the given path. @@ -219,7 +220,7 @@ def rev_older_than(self, rev1, rev2): """Provides a total order over revisions. - + Return `True` if `rev1` is older than `rev2`, i.e. if `rev1` comes before `rev2` in the revision sequence. """ @@ -227,7 +228,7 @@ def get_youngest_rev_in_cache(self, db): """Return the youngest revision currently cached. - + The way revisions are sequenced is version control specific. By default, one assumes that the revisions are sequenced in time (... which is ''not'' correct for most VCS, including Subversion). @@ -255,11 +256,11 @@ def normalize_rev(self, rev): """Return a canonical representation of a revision. - It's up to the backend to decide which string values of `rev` - (usually provided by the user) should be accepted, and how they + It's up to the backend to decide which string values of `rev` + (usually provided by the user) should be accepted, and how they should be normalized. Some backends may for instance want to match against known tags or branch names. - + In addition, if `rev` is `None` or '', the youngest revision should be returned. """ @@ -268,11 +269,11 @@ def short_rev(self, rev): """Return a compact representation of a revision in the repos.""" return self.normalize_rev(rev) - + def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=1): """Generates changes corresponding to generalized diffs. - + Generator that yields change tuples (old_node, new_node, kind, change) for each node change between the two arbitrary (path,rev) pairs. @@ -293,12 +294,12 @@ # # Those properties must be set by subclasses. # - created_rev = None + created_rev = None created_path = None def __init__(self, path, rev, kind): assert kind in (Node.DIRECTORY, Node.FILE), \ - "Unknown node kind %s" % kind + u"Type du noeud inconnu %s" % kind self.path = unicode(path) self.rev = rev self.kind = kind @@ -321,7 +322,7 @@ def get_history(self, limit=None): """Provide backward history for this Node. - + Generator that yields `(path, rev, chg)` tuples, one for each revision in which the node was changed. This generator will follow copies and moves of a node (if the underlying version control system supports @@ -409,7 +410,7 @@ Warning: API will be improved (see #1601 and #2545). """ - + def get_changes(self): """Generator that produces a tuple for every change in the changeset @@ -433,7 +434,7 @@ class Authorizer(object): """Controls the view access to parts of the repository. - + Base class for authorizers that are responsible to granting or denying access to view certain parts of a repository. """ @@ -441,12 +442,12 @@ def assert_permission(self, path): if not self.has_permission(path): raise PermissionDenied, \ - 'Insufficient permissions to access %s' % path + u"Droits d'accès insuffisants pour accèder à %s" % path def assert_permission_for_changeset(self, rev): if not self.has_permission_for_changeset(rev): raise PermissionDenied, \ - 'Insufficient permissions to access changeset %s' % rev + 'Permissions insuffisantes pour accéder à l\'enregistrement %s' % rev def has_permission(self, path): return True diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/cache.py trac-0.10.4-PKG/trac/versioncontrol/cache.py --- trac-0.10.4/trac/versioncontrol/cache.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/cache.py 2007-08-24 11:58:52.000000000 +0200 @@ -63,7 +63,7 @@ "WHERE rev=%s", (cset.date, cset.author, cset.message, (str(cset.rev)))) self.db.commit() - + def sync(self, feedback=None): cursor = self.db.cursor() @@ -72,16 +72,16 @@ metadata = {} for name, value in cursor: metadata[name] = value - + # -- check that we're populating the cache for the correct repository repository_dir = metadata.get(CACHE_REPOSITORY_DIR) if repository_dir: if repository_dir != self.name: self.log.info("'repository_dir' has changed from %r to %r" % (repository_dir, self.name)) - raise TracError("The 'repository_dir' has changed, " - "a 'trac-admin resync' operation is needed.") - elif repository_dir is None: # + raise TracError(u"Le chemin du dépôt a changé, une operation " + u"'trac-admin resync' est nécessaire.") + elif repository_dir is None: # self.log.info('Storing initial "repository_dir": %s' % self.name) cursor.execute("INSERT INTO system (name,value) VALUES (%s,%s)", (CACHE_REPOSITORY_DIR, self.name,)) @@ -94,8 +94,8 @@ # -- retrieve the youngest revision cached so far if CACHE_YOUNGEST_REV not in metadata: - raise TracError('Missing "youngest_rev" in cache metadata') - + raise TracError(u'"youngest_rev" est manquant dans le cache des métadonnées') + self.youngest = metadata[CACHE_YOUNGEST_REV] if self.youngest: @@ -149,7 +149,7 @@ try: while next_youngest is not None: - + # 1.1 Attempt to resync the 'revision' table self.log.info("Trying to sync revision [%s]" % next_youngest) @@ -160,7 +160,7 @@ "VALUES (%s,%s,%s,%s)", (str(next_youngest), cset.date, cset.author, cset.message)) - except Exception, e: # *another* 1.1. resync attempt won + except Exception, e: # *another* 1.1. resync attempt won self.log.warning('Revision %s already cached: %s' % (next_youngest, e)) # also potentially in progress, so keep ''previous'' @@ -186,7 +186,7 @@ path, kind, action, bpath, brev)) # 1.3. iterate (1.1 should always succeed now) - self.youngest = next_youngest + self.youngest = next_youngest next_youngest = self.repos.next_rev(next_youngest) # 1.4. update 'youngest_rev' metadata (minimize failures at 0.) diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/svn_fs.py trac-0.10.4-PKG/trac/versioncontrol/svn_fs.py --- trac-0.10.4/trac/versioncontrol/svn_fs.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/svn_fs.py 2007-08-24 12:00:38.000000000 +0200 @@ -65,7 +65,7 @@ def apr_pool_clear(): pass Editor = object delta = core = dummy_svn() - + _kindmap = {core.svn_node_dir: Node.DIRECTORY, core.svn_node_file: Node.FILE} @@ -78,11 +78,11 @@ Returns an UTF-8 encoded string suitable for the Subversion python bindings. """ return '/'.join([path.strip('/') for path in args]).encode('utf-8') - + def _from_svn(path): """Expect an UTF-8 encoded string and transform it to an `unicode` object""" return path and path.decode('utf-8') - + def _normalize_path(path): """Remove leading "/", except for the root.""" return path and path.strip('/') or '/' @@ -121,7 +121,7 @@ apr_pool_destroy = staticmethod(core.apr_pool_destroy) apr_terminate = staticmethod(core.apr_terminate) apr_pool_clear = staticmethod(core.apr_pool_clear) - + def __init__(self, parent_pool=None): """Create a new memory pool""" @@ -237,7 +237,7 @@ authz = SubversionAuthorizer(self.env, crepos, authname) repos.authz = crepos.authz = authz return crepos - + class SubversionRepository(Repository): @@ -249,24 +249,24 @@ self.path = path # might be needed by __del__()/close() self.log = log if core.SVN_VER_MAJOR < 1: - raise TracError("Subversion >= 1.0 required: Found %d.%d.%d" % \ + raise TracError(u"Subversion >= 1.0 requis: version %d.%d.%d trouvée" % \ (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_MICRO)) self.pool = Pool() - + # Remove any trailing slash or else subversion might abort if isinstance(path, unicode): path = path.encode('utf-8') path = os.path.normpath(path).replace('\\', '/') self.path = repos.svn_repos_find_root_path(path, self.pool()) if self.path is None: - raise TracError("%s does not appear to be a Subversion repository." \ + raise TracError(u"%s ne semble pas être un dépot Subversion." \ % path) self.repos = repos.svn_repos_open(self.path, self.pool()) self.fs_ptr = repos.svn_repos_fs(self.repos) - + uuid = fs.get_uuid(self.fs_ptr, self.pool()) name = 'svn:%s:%s' % (uuid, _from_svn(path)) @@ -365,7 +365,7 @@ core.SubversionException): # in 1.3.x pass return None - + def get_oldest_rev(self): if self.oldest is None: @@ -394,7 +394,7 @@ youngest = self.youngest_rev subpool = Pool(self.pool) while next <= youngest: - subpool.clear() + subpool.clear() try: for _, next in self._history(_to_svn(self.scope, path), rev+1, next, subpool): @@ -469,16 +469,17 @@ if self.has_node(old_path, old_rev): old_node = self.get_node(old_path, old_rev) else: - raise NoSuchNode(old_path, old_rev, 'The Base for Diff is invalid') + raise NoSuchNode(old_path, old_rev, 'La Base pour le Diff est invalide') if self.has_node(new_path, new_rev): new_node = self.get_node(new_path, new_rev) else: - raise NoSuchNode(new_path, new_rev, 'The Target for Diff is invalid') + raise NoSuchNode(new_path, new_rev, 'La Cible pour le Diff est invalide') if new_node.kind != old_node.kind: - raise TracError('Diff mismatch: Base is a %s (%s in revision %s) ' - 'and Target is a %s (%s in revision %s).' \ - % (old_node.kind, old_path, old_rev, - new_node.kind, new_path, new_rev)) + raise TracError(u'Erreur de calcul des différences: La base est un' + u'%s (%s en révision %s) ' + u'et la cible est un %s (%s en révision %s).' \ + % (old_node.kind, old_path, old_rev, + new_node.kind, new_path, new_rev)) subpool = Pool(self.pool) if new_node.isdir: editor = DiffChangeEditor() @@ -670,7 +671,7 @@ changes = [] revroots = {} for path, change in editor.changes.items(): - + # Filtering on `path` if not (_is_path_within_scope(self.scope, path) and \ self.authz.has_permission(path)): @@ -712,7 +713,7 @@ revroots[base_rev] = b_root tmp.clear() cbase_path = fs.node_created_path(b_root, base_path, tmp()) - cbase_rev = fs.node_created_rev(b_root, base_path, tmp()) + cbase_rev = fs.node_created_rev(b_root, base_path, tmp()) # give up if the created path is outside the scope if _is_path_within_scope(self.scope, cbase_path): base_path, base_rev = cbase_path, cbase_rev @@ -751,11 +752,11 @@ # Note 2: the 'dir_baton' is the path of the parent directory # -class DiffChangeEditor(delta.Editor): +class DiffChangeEditor(delta.Editor): def __init__(self): self.deltas = [] - + # -- svn.delta.Editor callbacks def open_root(self, base_revision, dir_pool): diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/web_ui/browser.py trac-0.10.4-PKG/trac/versioncontrol/web_ui/browser.py --- trac-0.10.4/trac/versioncontrol/web_ui/browser.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/web_ui/browser.py 2007-08-24 12:04:21.000000000 +0200 @@ -51,7 +51,7 @@ downloadable_paths = ListOption('browser', 'downloadable_paths', '/trunk, /branches/*, /tags/*', doc= """List of repository paths that can be downloaded. - + Leave the option empty if you want to disable all downloads, otherwise set it to a comma-separated list of authorized paths (those paths are glob patterns, i.e. "*" can be used as a wild card) @@ -61,14 +61,14 @@ 'false', """Whether attachments should be rendered in the browser, or only made downloadable. - + Pretty much any file may be interpreted as HTML by the browser, which allows a malicious user to attach a file containing cross-site scripting attacks. - + For public sites where anonymous users can create attachments it is recommended to leave this option disabled (which is the default).""") - + # INavigationContributor methods def get_active_navigation_item(self, req): @@ -78,7 +78,7 @@ if not req.perm.has_permission('BROWSER_VIEW'): return yield ('mainnav', 'browser', - html.A('Browse Source', href=req.href.browser())) + html.A(u'Explorateur', href=req.href.browser())) # IPermissionRequestor methods @@ -135,7 +135,7 @@ path_links = get_path_links(req.href, path, rev) if len(path_links) > 1: - add_link(req, 'up', path_links[-2]['href'], 'Parent directory') + add_link(req, 'up', path_links[-2]['href'], u'Répertoire parent') req.hdf['browser.path'] = path_links if node.isdir: @@ -200,7 +200,7 @@ filter(None, [fnmatchcase(node.path, p) for p in patterns]): zip_href = req.href.changeset(rev or repos.youngest_rev, node.path, old=rev, old_path='/', format='zip') - add_link(req, 'alternate', zip_href, 'Zip Archive', + add_link(req, 'alternate', zip_href, u'Archive Zip', 'application/zip', 'zip') req.hdf['browser'] = {'order': order, 'desc': desc and 1 or 0, @@ -230,7 +230,7 @@ req.send_header('Last-Modified', http_date(node.last_modified)) if not self.render_unsafe_content: # Force browser to download files instead of rendering - # them, since they might contain malicious code enabling + # them, since they might contain malicious code enabling # XSS attacks req.send_header('Content-Disposition', 'attachment') req.end_headers() @@ -241,7 +241,7 @@ req.write(chunk) chunk = content.read(CHUNK_SIZE) else: - # The changeset corresponding to the last change on `node` + # The changeset corresponding to the last change on `node` # is more interesting than the `rev` changeset. changeset = repos.get_changeset(node.rev) @@ -260,17 +260,17 @@ 'size': pretty_size(node.content_length), 'author': changeset.author or 'anonymous', 'message': message - } + } # add ''Plain Text'' alternate link if needed if not is_binary(chunk) and mime_type != 'text/plain': plain_href = req.href.browser(node.path, rev=rev, format='txt') - add_link(req, 'alternate', plain_href, 'Plain Text', + add_link(req, 'alternate', plain_href, u'Texte brut', 'text/plain') # add ''Original Format'' alternate link (always) raw_href = req.href.browser(node.path, rev=rev, format='raw') - add_link(req, 'alternate', raw_href, 'Original Format', mime_type) + add_link(req, 'alternate', raw_href, u'Format original', mime_type) self.log.debug("Rendering preview of node %s@%s with mime-type %s" % (node.name, str(rev), mime_type)) diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/web_ui/changeset.py trac-0.10.4-PKG/trac/versioncontrol/web_ui/changeset.py --- trac-0.10.4/trac/versioncontrol/web_ui/changeset.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/web_ui/changeset.py 2007-08-24 12:04:21.000000000 +0200 @@ -88,7 +88,7 @@ wiki_format_messages = BoolOption('changeset', 'wiki_format_messages', 'true', """Whether wiki formatting should be applied to changeset messages. - + If this option is disabled, changeset messages will be rendered as pre-formatted text.""") @@ -229,17 +229,17 @@ rpath = new_path.replace('/','_') if chgset: if restricted: - filename = 'changeset_%s_r%s' % (rpath, new) + filename = 'enregistrement_%s_r%s' % (rpath, new) else: - filename = 'changeset_r%s' % new + filename = 'enregistrement_r%s' % new else: if restricted: - filename = 'diff-%s-from-r%s-to-r%s' \ + filename = 'diff-%s-de-r%s-a-r%s' \ % (rpath, old, new) elif old_path == '/': # special case for download (#238) filename = '%s-r%s' % (rpath, old) else: - filename = 'diff-from-%s-r%s-to-%s-r%s' \ + filename = 'diff-de-%s-r%s-a-%s-r%s' \ % (old_path.replace('/','_'), old, rpath, new) if format == 'diff': self._render_diff(req, filename, repos, diff_args, @@ -259,9 +259,9 @@ 'new': new, 'old_path': old_path, 'old': old}) - add_link(req, 'alternate', '?format=diff&'+diff_params, 'Unified Diff', + add_link(req, 'alternate', '?format=diff&'+diff_params, u'Diff unifié', 'text/plain', 'diff') - add_link(req, 'alternate', '?format=zip&'+diff_params, 'Zip Archive', + add_link(req, 'alternate', '?format=zip&'+diff_params, u'Archive Zip', 'application/zip', 'zip') add_stylesheet(req, 'common/css/changeset.css') add_stylesheet(req, 'common/css/diff.css') @@ -304,9 +304,9 @@ def _changeset_title(rev): if restricted: - return 'Changeset %s for %s' % (rev, path) + return u'Version %s pour %s' % (rev, path) else: - return 'Changeset %s' % rev + return u'Version %s' % rev title = _changeset_title(rev) properties = [] @@ -335,7 +335,7 @@ prev_path = prev_rev = None else: add_link(req, 'first', req.href.changeset(oldest_rev), - 'Changeset %s' % oldest_rev) + u'Version %s' % oldest_rev) prev_path = diff.old_path prev_rev = repos.previous_rev(chgset.rev) if prev_rev: @@ -353,7 +353,7 @@ next_href = req.href.changeset(next_rev) else: add_link(req, 'last', req.href.changeset(youngest_rev), - 'Changeset %s' % youngest_rev) + u'Version %s' % youngest_rev) next_rev = repos.next_rev(chgset.rev) if next_rev: next_href = req.href.changeset(next_rev) @@ -614,11 +614,11 @@ def title_for_diff(self, diff): if diff.new_path == diff.old_path: # ''diff between 2 revisions'' mode - return 'Diff r%s:%s for %s' \ + return u'Diff r%s:%s pour %s' \ % (diff.old_rev or 'latest', diff.new_rev or 'latest', diff.new_path or '/') else: # ''arbitrary diff'' mode - return 'Diff from %s@%s to %s@%s' \ + return u'Diff de %s@%s à %s@%s' \ % (diff.old_path or '/', diff.old_rev or 'latest', diff.new_path or '/', diff.new_rev or 'latest') @@ -626,7 +626,7 @@ def get_timeline_filters(self, req): if req.perm.has_permission('CHANGESET_VIEW'): - yield ('changeset', 'Repository checkins') + yield ('changeset', u'Ajouts au dépôt') def get_timeline_events(self, req, start, stop, filters): if 'changeset' in filters: @@ -644,7 +644,7 @@ shortlog = shorten_line(message) if format == 'rss': - title = Markup('Changeset [%s]: %s', chgset.rev, shortlog) + title = Markup(u'Version [%s]: %s', chgset.rev, shortlog) href = req.abs_href.changeset(chgset.rev) if wiki_format: message = wiki_to_html(message, self.env, req, db, @@ -652,7 +652,7 @@ else: message = html.PRE(message) else: - title = Markup('Changeset [%s] by %s', chgset.rev, + title = Markup(u'Version [%s] par %s', chgset.rev, chgset.author) href = req.href.changeset(chgset.rev) @@ -750,7 +750,7 @@ def get_search_filters(self, req): if req.perm.has_permission('CHANGESET_VIEW'): - yield ('changeset', 'Changesets') + yield ('changeset', u'Versions') def get_search_results(self, req, terms, filters): if not 'changeset' in filters: diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/web_ui/log.py trac-0.10.4-PKG/trac/versioncontrol/web_ui/log.py --- trac-0.10.4/trac/versioncontrol/web_ui/log.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/web_ui/log.py 2007-08-24 12:05:20.000000000 +0200 @@ -78,7 +78,7 @@ stop_rev = unicode(repos.normalize_rev(stop_rev)) if repos.rev_older_than(rev, stop_rev): rev, stop_rev = stop_rev, rev - + req.hdf['title'] = path + ' (log)' req.hdf['log'] = { 'mode': mode, @@ -94,11 +94,11 @@ path_links = get_path_links(req.href, path, rev) req.hdf['log.path'] = path_links if path_links: - add_link(req, 'up', path_links[-1]['href'], 'Parent directory') + add_link(req, 'up', path_links[-1]['href'], u'Répertoire parent') # The `history()` method depends on the mode: - # * for ''stop on copy'' and ''follow copies'', it's `Node.history()` - # * for ''show only add, delete'' it's`Repository.get_path_history()` + # * for ''stop on copy'' and ''follow copies'', it's `Node.history()` + # * for ''show only add, delete'' it's`Repository.get_path_history()` if mode == 'path_history': def history(limit): for h in repos.get_path_history(path, rev, limit): @@ -134,9 +134,9 @@ previous_path = old_path if info == []: # FIXME: we should send a 404 error here - raise TracError("The file or directory '%s' doesn't exist " - "at revision %s or at any previous revision." - % (path, rev), 'Nonexistent path') + raise TracError(u"Le fichier ou le répertoire '%s' n'existe pas " + u"en révision %s ou pour toute révision précédente." + % (path, rev), u'Chemin inexistant') def make_log_href(path, **args): link_rev = rev @@ -152,11 +152,11 @@ next_rev = info[-1]['rev'] next_path = info[-1]['path'] add_link(req, 'next', make_log_href(next_path, rev=next_rev), - 'Revision Log (restarting at %s, rev. %s)' + u'Journal des révisions (repartant de %s, rév. %s)' % (next_path, next_rev)) # now, only show 'limit' results del info[-1] - + req.hdf['log.items'] = info revs = [i['rev'] for i in info] @@ -202,18 +202,18 @@ add_stylesheet(req, 'common/css/diff.css') rss_href = make_log_href(path, format='rss', stop_rev=stop_rev) - add_link(req, 'alternate', rss_href, 'RSS Feed', 'application/rss+xml', + add_link(req, 'alternate', rss_href, u'Flux RSS', 'application/rss+xml', 'rss') changelog_href = make_log_href(path, format='changelog', stop_rev=stop_rev) - add_link(req, 'alternate', changelog_href, 'ChangeLog', 'text/plain') + add_link(req, 'alternate', changelog_href, u'ChangeLog', 'text/plain') return 'log.cs', None # IWikiSyntaxProvider methods REV_RANGE = "%s[-:]%s" % ((ChangesetModule.CHANGESET_ID,)*2) - + def get_wiki_syntax(self): yield ( # [...] form, starts with optional intertrac: [T... or [trac ... diff --exclude=.svn -Naur trac-0.10.4/trac/versioncontrol/web_ui/util.py trac-0.10.4-PKG/trac/versioncontrol/web_ui/util.py --- trac-0.10.4/trac/versioncontrol/web_ui/util.py 2007-04-20 15:41:47.000000000 +0200 +++ trac-0.10.4-PKG/trac/versioncontrol/web_ui/util.py 2007-10-19 12:50:23.000000000 +0200 @@ -22,7 +22,7 @@ from trac.core import TracError from trac.util.datefmt import format_datetime, pretty_timedelta from trac.util.html import escape, html, Markup -from trac.util.text import shorten_line +from trac.util.text import to_unicode, shorten_line from trac.versioncontrol.api import NoSuchNode, NoSuchChangeset from trac.wiki import wiki_to_html, wiki_to_oneliner @@ -94,14 +94,14 @@ return path, rev, line def get_existing_node(req, repos, path, rev): - try: - return repos.get_node(path, rev) + try: + return repos.get_node(path, rev) except NoSuchNode, e: - raise TracError(Markup('%s

    You can search ' - 'in the repository history to see if that path ' - 'existed but was later removed.

    ', e.message, - req.href.log(path, rev=rev, - mode='path_history'))) + raise TracError(Markup(u'%s

    Vous pouvez rechercher ' + u'dans l\'historique du dépôt pour voir si le ' + u'chemin a existé mais a ensuite été supprimé.

    ', + to_unicode(e.message), req.href.log(path, rev=rev, + mode='path_history'))) def render_node_property(env, name, value): """Renders a node property value to HTML. diff --exclude=.svn -Naur trac-0.10.4/trac/web/api.py trac-0.10.4-PKG/trac/web/api.py --- trac-0.10.4/trac/web/api.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/api.py 2007-08-24 12:07:43.000000000 +0200 @@ -119,7 +119,7 @@ class Request(object): """Represents a HTTP request/response pair. - + This class provides a convenience API over WSGI. """ args = None @@ -131,7 +131,7 @@ def __init__(self, environ, start_response): """Create the request wrapper. - + @param environ: The WSGI environment dict @param start_response: The WSGI callback for starting the response """ @@ -337,7 +337,7 @@ self.end_headers() if self.method != 'HEAD': - self.write('Redirecting...') + self.write(u'Redirection...') raise RequestDone def display(self, template, content_type='text/html', status=200): @@ -345,7 +345,7 @@ `template` parameter, which can be either the name of the template file, or an already parsed `neo_cs.CS` object. """ - assert self.hdf, 'HDF dataset not available' + assert self.hdf, u'Données HDF non disponibles' if self.args.has_key('hdfdump'): # FIXME: the administrator should probably be able to disable HDF # dumps @@ -399,7 +399,7 @@ def send_file(self, path, mimetype=None): """Send a local file to the browser. - + This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file @@ -407,7 +407,7 @@ "304 Not Modified" response if it matches. """ if not os.path.isfile(path): - raise HTTPNotFound("File %s not found" % path) + raise HTTPNotFound(u"Fichier %s non trouvé" % path) stat = os.stat(path) last_modified = http_date(stat.st_mtime) @@ -475,11 +475,11 @@ # implementing classes should set this property to `True` if they # don't need session and authentication related information anonymous_request = False - + # implementing classes should set this property to `False` if they # don't need the HDF data and don't produce content using a template use_template = True - + def match_request(req): """Return whether the handler wants to process the given request.""" @@ -502,14 +502,14 @@ def pre_process_request(req, handler): """Called after initial handler selection, and can be used to change the selected handler or redirect request. - + Always returns the request handler, even if unchanged. """ def post_process_request(req, template, content_type): """Do any post-processing the request might need; typically adding values to req.hdf, or changing template or mime type. - + Always returns a tuple of (template, content_type), even if unchanged. """ diff --exclude=.svn -Naur trac-0.10.4/trac/web/auth.py trac-0.10.4-PKG/trac/web/auth.py --- trac-0.10.4/trac/web/auth.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/auth.py 2007-08-24 12:07:43.000000000 +0200 @@ -29,7 +29,7 @@ import time import urllib2 -from trac.config import BoolOption +from trac.config import BoolOption, Option from trac.core import * from trac.web.api import IAuthenticator, IRequestHandler from trac.web.chrome import INavigationContributor @@ -59,6 +59,9 @@ ignore_case = BoolOption('trac', 'ignore_auth_case', 'false', """Whether case should be ignored for login names (''since 0.9'').""") + logout_redirect = Option('trac', 'logout_redirect', '', + """URL de redirection sur le logout""") + # IAuthenticator methods def authenticate(self, req): @@ -83,12 +86,12 @@ def get_navigation_items(self, req): if req.authname and req.authname != 'anonymous': - yield ('metanav', 'login', 'logged in as %s' % req.authname) + yield ('metanav', 'login', u'Connecté sous %s' % req.authname) yield ('metanav', 'logout', - html.A('Logout', href=req.href.logout())) + html.A(u'Déconnexion', href=req.href.logout())) else: yield ('metanav', 'login', - html.A('Login', href=req.href.login())) + html.A(u'Connexion', href=req.href.login())) # IRequestHandler methods @@ -112,17 +115,17 @@ cookie identifying the user on subsequent requests is sent back to the client. - If the Authenticator was created with `ignore_case` set to true, then + If the Authenticator was created with `ignore_case` set to true, then the authentication name passed from the web server in req.remote_user will be converted to lower case before being used. This is to avoid problems on installations authenticating against Windows which is not case sensitive regarding user names and domain names """ if not req.remote_user: - raise TracError(html("Authentication information not available. " - "Please refer to the ", - html.a('installation documentation', - title="Configuring Authentication", + raise TracError(html(u"Pas d'information d'authentification disponible. " + u"Merci de vous référer à la ", + html.a(u"documentation d'installation", + title="Configuration de l'authentification", href=req.href.wiki('TracInstall') + "#ConfiguringAuthentication"), ".")) remote_user = req.remote_user @@ -130,13 +133,15 @@ remote_user = remote_user.lower() assert req.authname in ('anonymous', remote_user), \ - 'Already logged in as %s.' % req.authname + u'Déjà connecté sous %s.' % req.authname cookie = hex_entropy() db = self.env.get_db_cnx() cursor = db.cursor() - cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) " - "VALUES (%s, %s, %s, %s)", (cookie, remote_user, + # Effacer aussi tout cookie pré-existant de l'utilisateur en cas de non logout + cursor.execute("DELETE FROM auth_cookie WHERE name=%s ; " + "INSERT INTO auth_cookie (cookie,name,ipnr,time) " + "VALUES (%s, %s, %s, %s)", (remote_user, cookie, remote_user, req.remote_addr, int(time.time()))) db.commit() @@ -191,10 +196,12 @@ def _redirect_back(self, req): """Redirect the user back to the URL she came from.""" - referer = req.get_header('Referer') - if referer and not referer.startswith(req.base_url): - # only redirect to referer if it is from the same site - referer = None + referer = self.logout_redirect + if not req.path_info.startswith('/logout') or not referer: + referer = req.get_header('Referer') + if referer and not referer.startswith(req.base_url): + # only redirect to referer if it is from the same site + referer = None req.redirect(referer or req.abs_href()) @@ -311,7 +318,7 @@ self.hash[u] = a1 if self.hash == {}: print >> sys.stderr, "Warning: found no users in realm:", self.realm - + def parse_auth_header(self, authorization): values = {} for value in urllib2.parse_http_list(authorization): diff --exclude=.svn -Naur trac-0.10.4/trac/web/chrome.py trac-0.10.4-PKG/trac/web/chrome.py --- trac-0.10.4/trac/web/chrome.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/chrome.py 2007-08-24 12:07:58.000000000 +0200 @@ -84,7 +84,7 @@ def get_active_navigation_item(req): """This method is only called for the `IRequestHandler` processing the request. - + It should return the name of the navigation item that should be highlighted as active/current. """ @@ -107,7 +107,7 @@ Each item in the list must be a `(prefix, abspath)` tuple. The `prefix` part defines the path in the URL that requests to these resources are prefixed with. - + The `abspath` is the absolute path to the directory containing the resources on the local file system. """ @@ -231,7 +231,7 @@ req.send_file(path, mimeview.get_mimetype(path)) self.log.warning('File %s not found in any of %s', filename, dirs) - raise HTTPNotFound('File %s not found', filename) + raise HTTPNotFound(u'Fichier %s non trouvé', filename) # ITemplateProvider methods @@ -244,10 +244,10 @@ return [self.env.get_templates_dir(), self.templates_dir] # IWikiSyntaxProvider methods - + def get_wiki_syntax(self): return [] - + def get_link_resolvers(self): yield ('htdocs', self._format_link) diff --exclude=.svn -Naur trac-0.10.4/trac/web/clearsilver.py trac-0.10.4-PKG/trac/web/clearsilver.py --- trac-0.10.4/trac/web/clearsilver.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/clearsilver.py 2007-08-24 12:08:14.000000000 +0200 @@ -77,7 +77,7 @@ Traceback (most recent call last): ... KeyError: 'undef' - + It may be preferable to return a default value if the given key does not exit. It will return 'None' when the specified key is not present: @@ -110,7 +110,7 @@ def __init__(self, loadpaths=[]): """Create a new HDF dataset. - + The loadpaths parameter can be used to specify a sequence of paths under which ClearSilver will search for template files: @@ -132,7 +132,8 @@ import neo_util self.hdf = neo_util.HDF() except ImportError, e: - raise TracError, "ClearSilver not installed (%s)" % e + raise TracError, \ + u"ClearSilver n'est pas installé (%s)" % e self['hdf.loadpaths'] = loadpaths @@ -159,7 +160,7 @@ def __setitem__(self, name, value): """Add data to the HDF dataset. - + The `name` parameter is the path of the node in dotted syntax. The `value` parameter can be a simple value such as a string or number, but also data structures such as dicts and lists. @@ -195,16 +196,16 @@ KeyError: 'test.none' """ self.set_value(name, value, True) - + def set_unescaped(self, name, value): """ Add data to the HDF dataset. - + This method works the same way as `__setitem__` except that `value` is not escaped if it is a string. """ self.set_value(name, value, False) - + def set_value(self, name, value, do_escape=True): """ Add data to the HDF dataset. @@ -213,7 +214,7 @@ self.hdf.setValue(prefix.encode('utf-8'), value.encode('utf-8')) def set_str(prefix, value): self.hdf.setValue(prefix.encode('utf-8'), str(value)) - + def add_value(prefix, value): if value is None: return diff --exclude=.svn -Naur trac-0.10.4/trac/web/_fcgi.py trac-0.10.4-PKG/trac/web/_fcgi.py --- trac-0.10.4/trac/web/_fcgi.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/_fcgi.py 2007-08-24 12:16:21.000000000 +0200 @@ -1,4 +1,4 @@ -# -*- coding: iso-8859-1 -*- +# -*- coding: utf-8 -*- # # Copyright (c) 2002, 2003, 2005, 2006 Allan Saddi # All rights reserved. diff --exclude=.svn -Naur trac-0.10.4/trac/web/href.py trac-0.10.4-PKG/trac/web/href.py --- trac-0.10.4/trac/web/href.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/href.py 2007-08-21 22:27:21.000000000 +0200 @@ -113,6 +113,9 @@ def __init__(self, base): self.base = base self._derived = {} + # Initialisation pour remplacer 'wiki' dans l'URL + self._wiki = None + self._replace_wiki = False def __call__(self, *args, **kw): href = self.base @@ -138,9 +141,27 @@ add_param(k, v) args = args[:-1] + # Contrôle de la traduction du chemin 'wiki' + _args = [] + _replace = False + for arg in args: + if arg == 'replace_wiki': + # L'argument suivant est l'URL de remplacement + self._replace_wiki = True + _replace = True + elif self._replace_wiki and _replace: + # Mettre à jour la valeur de remplacement + self._wiki = arg + _replace = False + elif self._replace_wiki and self._wiki != None and arg == 'wiki': + # Remplacer 'wiki' par la valeur mise à jour + _args.append(self._wiki) + elif arg != None: + # Partie normale de l'URL + _args.append(arg) + # build the path - path = '/'.join([unicode_quote(unicode(arg).strip('/')) for arg in args - if arg != None]) + path = '/'.join([unicode_quote(unicode(arg).strip('/')) for arg in _args]) if path: href += '/' + path diff --exclude=.svn -Naur trac-0.10.4/trac/web/main.py trac-0.10.4-PKG/trac/web/main.py --- trac-0.10.4/trac/web/main.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/main.py 2007-10-19 12:50:51.000000000 +0200 @@ -86,6 +86,9 @@ 'url': env.project_url } + # Insérer les traductions + hdf['translation'] = env.translations + if req: hdf['trac.href'] = { 'wiki': req.href.wiki(), @@ -131,11 +134,10 @@ filters = OrderedExtensionsOption('trac', 'request_filters', IRequestFilter, doc="""Ordered list of filters to apply to all requests (''since 0.10'').""") - default_handler = ExtensionOption('trac', 'default_handler', IRequestHandler, 'WikiModule', """Name of the component that handles requests to the base URL. - + Options include `TimelineModule`, `RoadmapModule`, `BrowserModule`, `QueryModule`, `ReportModule` and `NewticketModule` (''since 0.9'').""") @@ -152,7 +154,7 @@ def dispatch(self, req): """Find a registered handler that matches the request and let it process it. - + In addition, this method initializes the HDF data set and adds the web site chrome. """ @@ -161,6 +163,10 @@ # FIXME in 0.11: self.env.abs_href = Href(self.env.base_url) self.env.abs_href = req.abs_href + # Remplacer l'url wiki par sa traduction pour l'API URL + self.env.href.replace_wiki(self.env.config.get('trac', 'wiki_base_url')) + self.env.abs_href.replace_wiki(self.env.config.get('trac', 'wiki_base_url')) + # Select the component that should handle the request chosen_handler = None early_error = None @@ -191,9 +197,9 @@ chosen_handler = self._pre_process_request(req, chosen_handler) except: early_error = sys.exc_info() - + if not chosen_handler and not early_error: - early_error = (HTTPNotFound('No handler matched request to %s', + early_error = (HTTPNotFound(u'Aucun composant ne peut gérer la requête %s' % req.path_info), None, None) @@ -231,8 +237,10 @@ if ctype in ('application/x-www-form-urlencoded', 'multipart/form-data') and \ req.args.get('__FORM_TOKEN') != req.form_token: - raise HTTPBadRequest('Missing or invalid form token. ' - 'Do you have cookies enabled?') + raise HTTPBadRequest(u'Jeton de formulaire manquant ' + u'ou invalide. Votre navigateur ' + u'est-il configuré pour utiliser' + u' les cookies ?') resp = chosen_handler.process_request(req) if resp: @@ -256,13 +264,13 @@ except PermissionError, e: raise HTTPForbidden(to_unicode(e)) except TracError, e: - raise HTTPInternalError(e.message) + raise HTTPInternalError(to_unicode(e.message)) def _pre_process_request(self, req, chosen_handler): for f in self.filters: chosen_handler = f.pre_process_request(req, chosen_handler) return chosen_handler - + def _post_process_request(self, req, template=None, content_type=None): for f in reversed(self.filters): template, content_type = f.post_process_request(req, template, @@ -276,7 +284,7 @@ By requiring that every POST form to contain this value we're able to protect against CSRF attacks. Since this value is only known by the user and not by an attacker. - + If the the user does not have a `trac_form_token` cookie a new one is generated. """ @@ -286,11 +294,11 @@ req.outcookie['trac_form_token'] = hex_entropy(24) req.outcookie['trac_form_token']['path'] = req.base_path return req.outcookie['trac_form_token'].value - + def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. - + @param environ: the WSGI environment dict @param start_response: the WSGI callback for starting the response """ @@ -322,8 +330,8 @@ root_uri = options['TracUriRoot'].rstrip('/') request_uri = environ['REQUEST_URI'].split('?', 1)[0] if not request_uri.startswith(root_uri): - raise ValueError('TracUriRoot set to %s but request URL ' - 'is %s' % (root_uri, request_uri)) + raise ValueError(u'TracUriRoot défini pour %s mais la requète ' + u'pointe sur %s' % (root_uri, request_uri)) environ['SCRIPT_NAME'] = root_uri environ['PATH_INFO'] = urllib.unquote(request_uri[len(root_uri):]) @@ -375,15 +383,16 @@ env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): - start_response('404 Not Found', []) - return ['Environment not found'] + start_response(u'404 Non trouvé', []) + return [u'Environnement non trouvé'] if not env_path: - raise EnvironmentError('The environment options "TRAC_ENV" or ' - '"TRAC_ENV_PARENT_DIR" or the mod_python ' - 'options "TracEnv" or "TracEnvParentDir" are ' - 'missing. Trac requires one of these options ' - 'to locate the Trac environment(s).') + raise EnvironmentError(u'Les options d\'environnement "TRAC_ENV" ou ' + u'"TRAC_ENV_PARENT_DIR", ou bien les options ' + u'mod_python "TracEnv" ou "TracEnvParentDir" ne ' + u'sont pas définies. Trac a besoin d\'une de ces ' + u'options pour localiser le ou les environnements ' + u'Trac.') run_once = environ['wsgi.run_once'] env = env_error = None @@ -397,7 +406,7 @@ req = Request(environ, start_response) try: if not env and env_error: - from trac.config import default_dir + from trac.config import default_dir req.hdf = HDFWrapper([default_dir('templates')]) raise HTTPInternalError(env_error.message) try: @@ -415,9 +424,9 @@ if env: env.log.warn(e) if req.hdf: - req.hdf['title'] = e.reason or 'Error' + req.hdf['title'] = e.reason or u'Erreur' req.hdf['error'] = { - 'title': e.reason or 'Error', + 'title': e.reason or u'Erreur', 'type': 'TracError', 'message': e.message } @@ -430,9 +439,9 @@ env.log.exception(e) if req.hdf: - req.hdf['title'] = to_unicode(e) or 'Error' + req.hdf['title'] = to_unicode(e) or u'Erreur' req.hdf['error'] = { - 'title': to_unicode(e) or 'Error', + 'title': to_unicode(e) or u'Erreur', 'type': 'internal', 'traceback': get_last_traceback() } diff --exclude=.svn -Naur trac-0.10.4/trac/web/session.py trac-0.10.4-PKG/trac/web/session.py --- trac-0.10.4/trac/web/session.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/session.py 2007-08-24 12:15:35.000000000 +0200 @@ -53,7 +53,7 @@ self.get_session(req.authname, authenticated=True) def bake_cookie(self, expires=PURGE_AGE): - assert self.sid, 'Session ID not set' + assert self.sid, u'ID de session non défini' self.req.outcookie[COOKIE_KEY] = self.sid self.req.outcookie[COOKIE_KEY]['path'] = self.req.base_path self.req.outcookie[COOKIE_KEY]['expires'] = expires @@ -91,17 +91,18 @@ def change_sid(self, new_sid): assert self.req.authname == 'anonymous', \ - 'Cannot change ID of authenticated session' - assert new_sid, 'Session ID cannot be empty' + u"Impossible de changer l'identifiant d'une session authentifiée" + assert new_sid, u"L'identifiant de session ne peut être vide" if new_sid == self.sid: return db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT sid FROM session WHERE sid=%s", (new_sid,)) if cursor.fetchone(): - raise TracError(Markup('Session "%s" already exists.
    ' - 'Please choose a different session ID.', - new_sid), 'Error renaming session') + raise TracError(Markup(u"La session '%s' existe déjà.
    " + u"Merci de choisir un identifiant de session " + u"différent." % new_sid), \ + u'Erreur de renommage de session') self.env.log.debug('Changing session ID %s to %s' % (self.sid, new_sid)) cursor.execute("UPDATE session SET sid=%s WHERE sid=%s " "AND authenticated=0", (new_sid, self.sid)) @@ -117,14 +118,14 @@ is no preexisting session data for that user name. """ assert self.req.authname != 'anonymous', \ - 'Cannot promote session of anonymous user' + u'La promotion d\'une session d\'un utilisateur anonyme impossible' db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT authenticated FROM session " "WHERE sid=%s OR sid=%s ", (sid, self.req.authname)) authenticated_flags = [row[0] for row in cursor.fetchall()] - + if len(authenticated_flags) == 2: # There's already an authenticated session for the user, we # simply delete the anonymous session diff --exclude=.svn -Naur trac-0.10.4/trac/web/standalone.py trac-0.10.4-PKG/trac/web/standalone.py --- trac-0.10.4/trac/web/standalone.py 2007-04-20 15:41:51.000000000 +0200 +++ trac-0.10.4-PKG/trac/web/standalone.py 2007-08-24 12:16:13.000000000 +0200 @@ -113,7 +113,7 @@ def _auth_callback(option, opt_str, value, parser, cls): info = value.split(',', 3) if len(info) != 3: - raise OptionValueError("Incorrect number of parameters for %s" + raise OptionValueError(u"Nombre de parametres incorrects pour %s" % option) env_name, filename, realm = info diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/api.py trac-0.10.4-PKG/trac/wiki/api.py --- trac-0.10.4/trac/wiki/api.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/api.py 2007-08-23 22:26:07.000000000 +0200 @@ -50,7 +50,7 @@ class IWikiPageManipulator(Interface): """Extension point interface for components that need to to specific pre and post processing of wiki page changes. - + Unlike change listeners, a manipulator can reject changes being committed to the database. """ @@ -61,7 +61,7 @@ def validate_wiki_page(req, page): """Validate a wiki page after it's been populated from user input. - + Must return a list of `(field, message)` tuples, one for each problem detected. `field` can be `None` to indicate an overall problem with the page. Therefore, a return value of `[]` means everything is OK.""" @@ -82,7 +82,7 @@ class IWikiSyntaxProvider(Interface): - + def get_wiki_syntax(): """Return an iterable that provides additional wiki syntax. @@ -91,7 +91,7 @@ which will be called if there's a match. That function is of the form cb(formatter, ns, match). """ - + def get_link_resolvers(): """Return an iterable over (namespace, formatter) tuples. @@ -100,7 +100,7 @@ return some HTML fragment. The `label` is already HTML escaped, whereas the `target` is not. """ - + class WikiSystem(Component): """Represents the wiki system.""" @@ -203,7 +203,9 @@ helper_re = re.compile(r'\?P<([a-z\d_]+)>') for rule in syntax: helpers += helper_re.findall(rule)[1:] - rules = re.compile('(?:' + '|'.join(syntax) + ')') + to_compile = '(?:' + '|'.join(syntax) + ')' + self.log.debug('Compilation de l\'expression régulière "%s"' % to_compile) + rules = re.compile(to_compile) self._external_handlers = handlers self._helper_patterns = helpers self._compiled_rules = rules @@ -246,7 +248,7 @@ if self.split_page_names: return re.sub(r"([a-z])([A-Z][a-z])", r"\1 \2", page) return page - + def get_wiki_syntax(self): from trac.wiki.formatter import Formatter wiki_page_name = ( @@ -254,13 +256,13 @@ r"(?:#%s)?" % self.XML_NAME + # optional fragment id r"(?=:(?:\Z|\s)|[^:a-zA-Z]|\s|\Z)" # what should follow it ) - + # Regular WikiPageNames def wikipagename_link(formatter, match, fullmatch): return self._format_link(formatter, 'wiki', match, self.format_page_name(match), self.ignore_missing_pages) - + yield (r"!?(?%s', self.name), + text = system_message(Markup(u'Erreur : Échec de chargement du' + u'transformateur %s', + self.name), self.error) else: text = self.processor(req, text) @@ -160,7 +161,7 @@ STARTBLOCK = "{{{" ENDBLOCK_TOKEN = r"\}\}\}" ENDBLOCK = "}}}" - + LINK_SCHEME = r"[\w.+-]+" # as per RFC 2396 INTERTRAC_SCHEME = r"[a-zA-Z.+-]*?" # no digits (support for shorthand links) @@ -172,7 +173,7 @@ LHREF_RELATIVE_TARGET = r"[/.#][^\s[\]]*" - XML_NAME = r"[\w:](?#%s)?$)" % XML_NAME, # * list r"(?P^(?P\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )", - # definition:: + # definition:: r"(?P^\s+((?:%s[^%s]*%s|%s.*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))" % (INLINE_TOKEN, INLINE_TOKEN, INLINE_TOKEN, STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, INLINE_TOKEN, STARTBLOCK[0]), @@ -258,7 +259,7 @@ return (target, query, fragment) # -- Pre- IWikiSyntaxProvider rules (Font styles) - + def tag_open_p(self, tag): """Do we currently have any open tag with `tag` as end-tag?""" return tag in self._open_tags @@ -354,7 +355,7 @@ label = ns+':'+target # use `http://target` else: # for `wiki:target` label = target # use only `target` - else: # e.g. `[search:]` + else: # e.g. `[search:]` label = ns else: label = self._unquote(label) @@ -388,7 +389,7 @@ sep = target.find(':') if sep != -1: url = '%s/%s/%s' % (url, target[:sep], target[sep + 1:]) - else: + else: url = '%s/search?q=%s' % (url, urllib.quote_plus(target)) else: url = '%s/intertrac/%s' % (url, urllib.quote(target)) @@ -408,7 +409,7 @@ return None def _make_interwiki_link(self, ns, target, label): - from trac.wiki.interwiki import InterWikiMap + from trac.wiki.interwiki import InterWikiMap interwiki = InterWikiMap(self.env) if ns in interwiki: url, title = interwiki.url(ns, target) @@ -430,7 +431,7 @@ return html.A(text, href=url) # WikiMacros - + def _macro_formatter(self, match, fullmatch): name = fullmatch.group('macroname') if name.lower() == 'br': @@ -442,7 +443,7 @@ except Exception, e: self.env.log.error('Macro %s(%s) failed' % (name, args), exc_info=True) - return system_message('Error: Macro %s(%s) failed' % (name, args), + return system_message(u'Erreur : Échec de la macro %s(%s)' % (name, args), e) # Headings @@ -502,7 +503,7 @@ self._tabstops = tabstops # Lists - + def _list_formatter(self, match, fullmatch): ldepth = len(fullmatch.group('ldepth')) listid = match[ldepth] @@ -523,7 +524,7 @@ class_ = 'upperalpha' self._set_list_depth(ldepth, type_, class_, start) return '' - + def _get_list_depth(self): """Return the space offset associated to the deepest opened list.""" return self._list_stack and self._list_stack[-1][1] or 0 @@ -658,7 +659,7 @@ self.in_quote = True # Table - + def _last_table_cell_formatter(self, match, fullmatch): return '' @@ -715,7 +716,7 @@ self.paragraph_open = 0 # Code blocks - + def handle_code_block(self, line): if line.strip() == Formatter.STARTBLOCK: self.in_code_block += 1 @@ -741,7 +742,7 @@ name = match.group(1) self.code_processor = WikiProcessor(self.env, name) else: - self.code_text += line + os.linesep + self.code_text += line + os.linesep self.code_processor = WikiProcessor(self.env, 'default') else: self.code_text += line + os.linesep @@ -751,7 +752,7 @@ self.handle_code_block(Formatter.ENDBLOCK) # -- Wiki engine - + def handle_match(self, fullmatch): for itype, match in fullmatch.groupdict().items(): if match and not itype in self.wiki.helper_patterns: @@ -929,7 +930,7 @@ class OutlineFormatter(Formatter): """Special formatter that generates an outline of all the headings.""" flavor = 'outline' - + def __init__(self, env, absurls=False, db=None): Formatter.__init__(self, env, None, absurls, db) @@ -976,16 +977,16 @@ class LinkFormatter(OutlineFormatter): """Special formatter that focuses on TracLinks.""" flavor = 'link' - + def __init__(self, env, absurls=False, db=None): OutlineFormatter.__init__(self, env, absurls, db) - + def _heading_formatter(self, match, fullmatch): return '' - + def match(self, wikitext): """Return the Wiki match found at the beginning of the `wikitext`""" - self.reset() + self.reset() match = re.match(self.wiki.rules, wikitext) if match: return self.handle_match(match) diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/intertrac.py trac-0.10.4-PKG/trac/wiki/intertrac.py --- trac-0.10.4/trac/wiki/intertrac.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/intertrac.py 2007-08-24 12:20:07.000000000 +0200 @@ -41,13 +41,13 @@ def process_request(self, req): link = req.args.get('link', '') if not link: - raise TracError('No TracLinks given') + raise TracError(u'Aucun lien TracLinks fourni') link_elt = wiki_to_link(link, self.env, req) if isinstance(link_elt, Element): href = link_elt.attr['href'] if href: req.redirect(href) - raise TracError('"%s" is not a TracLinks' % link) + raise TracError(u'"%s" n\'est pas un lien TracLinks' % link) # IWikiMacroProvider methods @@ -56,7 +56,7 @@ yield 'InterTrac' def get_macro_description(self, name): - return "Provide a list of known InterTrac prefixes." + return u"Fournit une liste des préfixes InterTrac connus." def render_macro(self, req, name, content): intertracs = {} @@ -73,7 +73,7 @@ intertrac = intertracs[prefix] if isinstance(intertrac, basestring): yield html.TR(html.TD(html.B(prefix)), - html.TD('Alias for ', html.B(intertrac))) + html.TD(u'Alias pour ', html.B(intertrac))) else: url = intertrac.get('url', '') if url: @@ -83,5 +83,5 @@ html.TD(html.A(title, href=url))) return html.TABLE(class_="wiki intertrac")( - html.TR(html.TH(html.EM('Prefix')), html.TH(html.EM('Trac Site'))), + html.TR(html.TH(html.EM('Prefix')), html.TH(html.EM(u'Site Trac'))), [generate_prefix(p) for p in sorted(intertracs.keys())]) diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/interwiki.py trac-0.10.4-PKG/trac/wiki/interwiki.py --- trac-0.10.4/trac/wiki/interwiki.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/interwiki.py 2007-08-24 12:20:19.000000000 +0200 @@ -131,7 +131,8 @@ yield 'InterWiki' def get_macro_description(self, name): - return "Provide a description list for the known InterWiki prefixes." + return u'Fournit une liste descriptive des differents préfixes ' \ + u'InterWiki connus.' def render_macro(self, req, name, content): from trac.util import sorted diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/macros.py trac-0.10.4-PKG/trac/wiki/macros.py --- trac-0.10.4/trac/wiki/macros.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/macros.py 2007-08-24 12:24:16.000000000 +0200 @@ -35,8 +35,7 @@ class WikiMacroBase(Component): - """Abstract base class for wiki macros.""" - + u"""Classe abstraite de base pour toutes les macros Wiki.""" implements(IWikiMacroProvider) abstract = True @@ -56,11 +55,11 @@ class TitleIndexMacro(WikiMacroBase): - """Inserts an alphabetic list of all wiki pages into the output. - - Accepts a prefix string as parameter: if provided, only pages with names - that start with the prefix are included in the resulting list. If this - parameter is omitted, all pages are listed. + u"""Insère une liste alphabetique de toutes les pages Wiki + + Accepte un paramètre précisant le préfixe: s'il est fourni, seules les + pages commencant par ce prefix seront incluses dans la liste résultante. + S'il n'est pas fournit, toutes les pages seront listées. """ def render_macro(self, req, name, content): @@ -74,16 +73,17 @@ class RecentChangesMacro(WikiMacroBase): - """Lists all pages that have recently been modified, grouping them by the - day they were last modified. + u"""Liste toutes les pages qui ont été modifiées récemment, en les regroupant + par le jour de leur dernière modification. - This macro accepts two parameters. The first is a prefix string: if - provided, only pages with names that start with the prefix are included in - the resulting list. If this parameter is omitted, all pages are listed. - - The second parameter is a number for limiting the number of pages returned. - For example, specifying a limit of 5 will result in only the five most - recently changed pages to be included in the list. + La macro accepte deux paramètres. Le premier est un préfixe: s'il est + fourni, seules les pages dont le nom débute par ce préfixe seront incluses + dans la liste résultante. Si ce paramètre est omis, toutes les pages sont + listées. + + Le second paramètre est une valeur limitant le nombre de pages retournées. + Par exemple, en spécifiant une limite de 5, seules les dernières 5 pages + récemment changées seront incluses dans la liste. """ def render_macro(self, req, name, content): @@ -127,7 +127,7 @@ html.UL([html.LI( html.A(wiki.format_page_name(name), href=req.href.wiki(name)), ' ', - version > 1 and + version > 1 and html.SMALL('(', html.A('diff', href=req.href.wiki(name, action='diff', version=version)), ')') \ @@ -137,24 +137,28 @@ class PageOutlineMacro(WikiMacroBase): - """Displays a structural outline of the current wiki page, each item in the - outline being a link to the corresponding heading. - - This macro accepts three optional parameters: - - * The first is a number or range that allows configuring the minimum and - maximum level of headings that should be included in the outline. For - example, specifying "1" here will result in only the top-level headings - being included in the outline. Specifying "2-3" will make the outline - include all headings of level 2 and 3, as a nested list. The default is - to include all heading levels. - * The second parameter can be used to specify a custom title (the default - is no title). - * The third parameter selects the style of the outline. This can be - either `inline` or `pullout` (the latter being the default). The `inline` - style renders the outline as normal part of the content, while `pullout` - causes the outline to be rendered in a box that is by default floated to - the right side of the other content. + u""" + Affiche la structure de la page Wiki courante, chaque élement de la + structure intégrant un lien vers la section correspondante. + + Cette macro accepte trois paramètes optionnels: + + * Le premier est un nombre ou un intervalle qui permet de configurer + les niveaux minimal et maximal des sous-sections qui doivent etre + inclus dans la structure generee. Par exemple, l'utilisation + de "1" permettra de n'inclure que les sous-sections de premier + niveau dans la structure. L'utilisation de "2-3" générera une + structure contenant toutes les sous-sections de niveau 2 et 3, + sous forme d'une liste imbriquée. Par défaut, toutes les + sous-sections sont incluses. + * Le second paramètre peut être utilisé pour préciser un titre (par défaut, + aucun titre). + * Le troisième paramètre permet de choisir le style de la présentation. Il + peut prendre les valeurs '''inline''' ou '''pullout''' (par défaut, + '''pullout'''). Le style '''inline''' permet d'intégrer la présentation + au contenu de la page, alors que '''pullout''' permet de placer la + structure dans un cadre qui est accollé sur la droite du reste du + contenu de la page. """ def render_macro(self, req, name, content): @@ -193,54 +197,54 @@ class ImageMacro(WikiMacroBase): - """Embed an image in wiki-formatted text. - - The first argument is the file specification. The file specification may - reference attachments or files in three ways: - * `module:id:file`, where module can be either '''wiki''' or '''ticket''', - to refer to the attachment named ''file'' of the specified wiki page or - ticket. - * `id:file`: same as above, but id is either a ticket shorthand or a Wiki - page name. - * `file` to refer to a local attachment named 'file'. This only works from - within that wiki page or a ticket. - - Also, the file specification may refer to repository files, using the - `source:file` syntax (`source:file@rev` works also). - - The remaining arguments are optional and allow configuring the attributes - and style of the rendered `` element: - * digits and unit are interpreted as the size (ex. 120, 25%) - for the image - * `right`, `left`, `top` or `bottom` are interpreted as the alignment for - the image - * `nolink` means without link to image source. - * `key=value` style are interpreted as HTML attributes or CSS style - indications for the image. Valid keys are: - * align, border, width, height, alt, title, longdesc, class, id - and usemap - * `border` can only be a number + u""" + Intègre une image dans du texte wiki. + + Le premier argument spécifie le fichier image. Le fichier image peut + référencer des pièces jointes ou des fichier de trois façons différentes: + * `module:id:file`, où le module peut être soit '''wiki''' soit '''ticket''', + pour référencer la pièce jointe nommée ''file'' à la page wiki ou au + ticket spécifié. + * `id:file`: même utilisation le premier point, mais 'id' est soit une + référence ticket soit le nom d'une page Wiki. + * `file` référence une pièce jointe nommée 'file'. Cette syntaxe ne + fonctionne que depuis une page Wiki ou un ticket. + + De plus, la spécification du fichier peut se référer à des fichiers du + dépôt, en utilisant la syntaxe `source:file` (`source:file@rev` fonctionne + également). + + Les arguments restants sont optionnels and permette de configurer les + attributs et le style de l'élément image (): + * les nombres et unités sont interprétés comme la taille (ex. 120, 25%) + de l'image + * `right`, `left`, `top` or `bottom` sont interprétés comme le + positionnement de l'image, respectivement droite, gauche, haut et bas. + * `nolink` désactive le lien vers l'image source + * le style `key=value` est interprété comme des attributs HTML de l'image + * le style `key:value` est interprété comme des indicateurs CSS de l'image - Examples: + Exemples: {{{ - [[Image(photo.jpg)]] # simplest - [[Image(photo.jpg, 120px)]] # with size - [[Image(photo.jpg, right)]] # aligned by keyword - [[Image(photo.jpg, nolink)]] # without link to source - [[Image(photo.jpg, align=right)]] # aligned by attribute + [[Image(photo.jpg)]] # le plus simple + [[Image(photo.jpg, 120px)]] # avec la taille + [[Image(photo.jpg, right)]] # aligné par mot clef + [[Image(photo.jpg, nolink)]] # sans lien vers la source + [[Image(photo.jpg, align=right)]] # aligné par un style HTML }}} - You can use image from other page, other ticket or other module. + Vous pouvez utiliser une image jointe à une autre page, un autre ticket ou + un autre module. {{{ - [[Image(OtherPage:foo.bmp)]] # if current module is wiki - [[Image(base/sub:bar.bmp)]] # from hierarchical wiki page - [[Image(#3:baz.bmp)]] # if in a ticket, point to #3 + [[Image(OtherPage:foo.bmp)]] # depuis une page wiki + [[Image(base/sub:bar.bmp)]] # depuis une page sous-page wiki + [[Image(#3:baz.bmp)]] # depuis un ticket, #3 ticket [[Image(ticket:36:boo.jpg)]] - [[Image(source:/images/bee.jpg)]] # straight from the repository! - [[Image(htdocs:foo/bar.png)]] # image file in project htdocs dir. + [[Image(source:/images/bee.jpg)]] # référence le dépôt + [[Image(htdocs:foo/bar.png)]] # fichier image depuis le rép. statique. }}} - ''Adapted from the Image.py macro created by Shun-ichi Goto + ''Basé sur une adaptation de la macro Image.py créée par Shun-ichi Goto '' """ @@ -252,7 +256,7 @@ # we expect the 1st argument to be a filename (filespec) args = content.split(',') if len(args) == 0: - raise Exception("No argument.") + raise Exception(u"Aucun argument") filespec = args[0] size_re = re.compile('[0-9]+%?$') attr_re = re.compile('(align|border|width|height|alt' @@ -289,15 +293,17 @@ # parse filespec argument to get module and id if contained. parts = filespec.split(':') url = None + wiki = self.env.config.get('trac', 'wiki_base_url') if len(parts) == 3: # module:id:attachment - if parts[0] in ['wiki', 'ticket']: + if parts[0] in [wiki, 'ticket']: module, id, file = parts else: - raise Exception("%s module can't have attachments" % parts[0]) + raise Exception(u"Le module %s ne peut pas posséder de fichiers " + "joints" % parts[0]) elif len(parts) == 2: from trac.versioncontrol.web_ui import BrowserModule try: - browser_links = [link for link,_ in + browser_links = [link for link,_ in BrowserModule(self.env).get_link_resolvers()] except Exception: browser_links = [] @@ -321,23 +327,27 @@ elif id in ('http', 'https', 'ftp'): # external URLs raw_url = url = desc = id+':'+file else: - module = 'wiki' + module = wiki elif len(parts) == 1: # attachment # determine current object # FIXME: should be retrieved from the formatter... # ...and the formatter should be provided to the macro file = filespec - module, id = 'wiki', 'WikiStart' + module, id = wiki, 'WikiStart' path_info = req.path_info.split('/',2) if len(path_info) > 1: module = path_info[1] if len(path_info) > 2: id = path_info[2] - if module not in ['wiki', 'ticket']: - raise Exception('Cannot reference local attachment from here') + if module not in [wiki, 'ticket']: + raise Exception(u'Impossible de référencer un fichier joint ' + u'depuis cet endroit') else: - raise Exception('No filespec given') + raise Exception(u'Pas de définition de fichier reçue') if not url: # this is an attachment + # Vérifier & mettre à jour le contenu de module dans le cas wiki + if wiki and module == 'wiki' and wiki != module: + module = wiki from trac.attachment import Attachment attachment = Attachment(self.env, module, id, file) url = attachment.href(req) @@ -356,14 +366,15 @@ class MacroListMacro(WikiMacroBase): - """Displays a list of all installed Wiki macros, including documentation if - available. + u"""Affiche une liste de toutes les macros Wiki installées, en incluant leur + éventuelle documentation. - Optionally, the name of a specific macro can be provided as an argument. In - that case, only the documentation for that macro will be rendered. + Il est également possible d'indiquer le nom d'une macro particulière comme + argument. Dans ce cas, seule la documentation de cette macro sera affichée. - Note that this macro will not be able to display the documentation of - macros if the `PythonOptimize` option is enabled for mod_python! + Si l'option `PythonOptimize` est activée pour mod_python, cette macro + ne sera pas capable d'afficher quelque documentation que ce soit sur les + autres macros. """ def render_macro(self, req, name, content): @@ -380,7 +391,7 @@ descr = wiki_to_html(descr or '', self.env, req) except Exception, e: descr = Markup(system_message( - "Error: Can't get description for macro %s" \ + u"Erreur: Impossible de trouver la description de la macro %s" \ % macro_name, e)) yield (macro_name, descr) @@ -391,12 +402,13 @@ class TracIniMacro(WikiMacroBase): - """Produce documentation for Trac configuration file. + u"""Génère la documentation pour le fichier de configuration de Trac. - Typically, this will be used in the TracIni page. - Optional arguments are a configuration section filter, - and a configuration option name filter: only the configuration - options whose section and name start with the filters are output. + Cette macro est typiquement utilisée dans la page TracIni. + Les arguments optionnels permettre de filtrer une section particulière + de configuration et le nom d'une option de cette section. + Seules les options dont la section et le nom commencent par les filtres + indiqués sont documentés. """ def render_macro(self, req, name, filter): @@ -419,9 +431,9 @@ class UserMacroProvider(Component): - """Adds macros that are provided as Python source files in the - `wiki-macros` directory of the environment, or the global macros - directory. + u"""Ajoute les macros fournies sous forme de fichiers source Python à partir + du répertoire `wiki-macros` de l'environnement Trac, ou du répertoire + global des macros """ implements(IWikiMacroProvider) @@ -466,4 +478,4 @@ macro_file = os.path.join(path, name + '.py') if os.path.isfile(macro_file): return imp.load_source(name, macro_file) - raise TracError, 'Macro %s not found' % name + raise TracError, u'Macro %s non trouvée' % name diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/model.py trac-0.10.4-PKG/trac/wiki/model.py --- trac-0.10.4/trac/wiki/model.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/model.py 2007-08-24 12:24:26.000000000 +0200 @@ -68,7 +68,7 @@ exists = property(fget=lambda self: self.version > 0) def delete(self, version=None, db=None): - assert self.exists, 'Cannot delete non-existent page' + assert self.exists, u'Impossible de supprimer une page inexistante' if not db: db = self.env.get_db_cnx() handle_ta = True @@ -131,7 +131,7 @@ cursor.execute("UPDATE wiki SET readonly=%s WHERE name=%s", (self.readonly, self.name)) else: - raise TracError('Page not modified') + raise TracError(u'Aucune modification apportée à la page') if handle_ta: db.commit() diff --exclude=.svn -Naur trac-0.10.4/trac/wiki/web_ui.py trac-0.10.4-PKG/trac/wiki/web_ui.py --- trac-0.10.4/trac/wiki/web_ui.py 2007-04-20 15:41:49.000000000 +0200 +++ trac-0.10.4-PKG/trac/wiki/web_ui.py 2007-08-24 12:28:31.000000000 +0200 @@ -28,7 +28,7 @@ from trac.util import get_reporter_id from trac.util.datefmt import format_datetime, pretty_timedelta from trac.util.html import html, Markup -from trac.util.text import shorten_line +from trac.util.text import shorten_line, translate from trac.versioncontrol.diff import get_diff_options, hdf_diff from trac.web.chrome import add_link, add_stylesheet, INavigationContributor from trac.web import HTTPNotFound, IRequestHandler @@ -51,7 +51,7 @@ # IContentConverter methods def get_supported_conversions(self): - yield ('txt', 'Plain Text', 'txt', 'text/x-trac-wiki', 'text/plain', 9) + yield ('txt', u'Texte standard', 'txt', 'text/x-trac-wiki', 'text/plain', 9) def convert_content(self, req, mimetype, content, key): return (content, 'text/plain;charset=utf-8') @@ -65,9 +65,9 @@ if not req.perm.has_permission('WIKI_VIEW'): return yield ('mainnav', 'wiki', - html.A('Wiki', href=req.href.wiki(), accesskey=1)) + html.A(translate(self.env,'Wiki',True), href=req.href.wiki(), accesskey=1)) yield ('metanav', 'help', - html.A('Help/Guide', href=req.href.wiki('TracGuide'), + html.A(u'Aide/Guide', href=req.href.wiki('TracGuide'), accesskey=6)) # IPermissionRequestor methods @@ -79,7 +79,9 @@ # IRequestHandler methods def match_request(self, req): - match = re.match(r'^/wiki(?:/(.*))?', req.path_info) + wiki_base_url = self.config.get('trac', 'wiki_base_url') + match_url = r'^/' + wiki_base_url + r'(?:/(.*))?' + match = re.match(match_url, req.path_info) if match: if match.group(1): req.args['page'] = match.group(1) @@ -127,7 +129,7 @@ elif action == 'history': self._render_history(req, db, page) else: - req.perm.assert_permission('WIKI_VIEW') + req.perm.assert_permission('WIKI_VIEW') format = req.args.get('format') if format: Mimeview(self.env).send_converted(req, 'text/x-trac-wiki', @@ -142,7 +144,7 @@ def get_timeline_filters(self, req): if req.perm.has_permission('WIKI_VIEW'): - yield ('wiki', 'Wiki changes') + yield ('wiki', u'Modifications %s' % translate(self.env,'wiki',False)) def get_timeline_events(self, req, start, stop, filters): if 'wiki' in filters: @@ -155,7 +157,7 @@ "FROM wiki WHERE time>=%s AND time<=%s", (start, stop)) for t,name,comment,author,version in cursor: - title = Markup('%s edited by %s', + title = Markup(u'%s édité par %s', wiki.format_page_name(name), author) diff_link = html.A('diff', href=href.wiki(name, action='diff', version=version)) @@ -230,10 +232,10 @@ for manipulator in self.page_manipulators: for field, message in manipulator.validate_wiki_page(req, page): if field: - raise InvalidWikiPage("The Wiki page field %s is invalid: %s" - % (field, message)) + raise InvalidWikiPage(u"Le champ %s de la page %s n'est pas valide: %s" + % (field, translate(self.env,'wiki',False), message)) else: - raise InvalidWikiPage("Invalid Wiki page: %s" % message) + raise InvalidWikiPage(u"Page %s non valide: %s" % (translate(self.env,'wiki',False),message)) page.save(get_reporter_id(req, 'author'), req.args.get('comment'), req.remote_addr) @@ -266,7 +268,7 @@ req.perm.assert_permission('WIKI_VIEW') if not page.exists: - raise TracError("Version %s of page %s does not exist" % + raise TracError(u"La version %s de la page %s n'existe pas" % (req.args.get('version'), page.name)) add_stylesheet(req, 'common/css/diff.css') @@ -397,7 +399,7 @@ req.perm.assert_permission('WIKI_VIEW') if not page.exists: - raise TracError, "Page %s does not exist" % page.name + raise TracError, u"La page %s n'existe pas" % page.name self._set_title(req, page, 'history') @@ -455,21 +457,22 @@ } else: if not req.perm.has_permission('WIKI_CREATE'): - raise HTTPNotFound('Page %s not found', page.name) - req.hdf['wiki.page_html'] = html.P('Describe "%s" here' % page_name) + raise HTTPNotFound(u'La page %s n\'existe pas', page.name) + req.hdf['wiki.page_html'] = html.P(u'Créer la page "%s" ici' % page_name) # Show attachments + wiki_base = self.env.config.get('trac', 'wiki_base_url') req.hdf['wiki.attachments'] = attachments_to_hdf(self.env, req, db, - 'wiki', page.name) + wiki_base, page.name) if req.perm.has_permission('WIKI_MODIFY'): - attach_href = req.href.attachment('wiki', page.name) + attach_href = req.href.attachment(wiki_base, page.name) req.hdf['wiki.attach_href'] = attach_href # ISearchSource methods def get_search_filters(self, req): if req.perm.has_permission('WIKI_VIEW'): - yield ('wiki', 'Wiki') + yield ('wiki', translate(self.env,'Wiki',True)) def get_search_results(self, req, terms, filters): if not 'wiki' in filters: diff --exclude=.svn -Naur trac-0.10.4/wiki-macros/FootNote.py trac-0.10.4-PKG/wiki-macros/FootNote.py --- trac-0.10.4/wiki-macros/FootNote.py 1970-01-01 01:00:00.000000000 +0100 +++ trac-0.10.4-PKG/wiki-macros/FootNote.py 2007-08-24 15:13:33.000000000 +0200 @@ -0,0 +1,73 @@ +"""Collates and generates foot-notes. Call the macro with the +foot-note content as the only argument: +{{{ + [[FootNote(This is a footnote)]] +}}} +Foot-notes are numbered by the order in which they appear. To create a +reference to an existing foot-note, pass the footnote number as +argument to the macro: +{{{ + [[FootNote(1)]] +}}} +In addition, identical foot-notes are coalesced into one entry. The +following will generate one footnote entry with two references: +{{{ + Some text[[FootNote(A footnote)]] and some more text [[FootNote(A footnote)]]. +}}} +A list of footnotes generated by one or more of the above commands is +produced by calling the macro without arguments: +{{{ + [[FootNote]] +}}} +Once a set of footnotes has been displayed, a complete new set of +footnotes can be created. This allows multiple sets of footnotes per +page. + +""" + +from StringIO import StringIO +from trac.util.html import escape +from trac.wiki.formatter import wiki_to_oneliner + +def unescape(text): + """Un-escapes &, <, > and \"""" + if not text: + return '' + return str(text).replace('&', '&') \ + .replace('<', '<') \ + .replace('>', '>') \ + .replace('"', '"') + +def execute(hdf, args, env): + if not hasattr(hdf, 'footnotes'): + hdf.footnotes = [] + hdf.footnote_set = 1 + # Display and clear footnotes... + if not args: + out = StringIO() + out.write('
    \n'); + out.write('
    \n'); + out.write('
      \n') + for i, v in enumerate(hdf.footnotes): + id = "%i.%i" % (hdf.footnote_set, i + 1) + out.write(u'
    1. %i. %s
    2. \n' % (id, id, i + 1, wiki_to_oneliner(unescape(v), env))) + out.write('
    \n') + out.write('
    \n'); + hdf.footnotes = [] + hdf.footnote_set += 1 + return out.getvalue() + else: + id = len(hdf.footnotes) + 1 + try: + id = int(args) + except ValueError: + existing = None + for index, note in enumerate(hdf.footnotes): + if args == note: + existing = note + id = index + 1 + break + if not existing: + hdf.footnotes.append(args) + full_id = "%i.%i" % (hdf.footnote_set, id) + return u'%i' % (args[:60] + "...", full_id, full_id, id) diff --exclude=.svn -Naur trac-0.10.4/wiki-macros/HelloWorld.py trac-0.10.4-PKG/wiki-macros/HelloWorld.py --- trac-0.10.4/wiki-macros/HelloWorld.py 2007-04-20 15:41:43.000000000 +0200 +++ trac-0.10.4-PKG/wiki-macros/HelloWorld.py 2007-09-03 17:10:44.000000000 +0200 @@ -1,4 +1,5 @@ -"""Example macro.""" +# -*- coding: utf-8 -*- +u"""Exemple de macro.""" from trac.util import escape def execute(hdf, txt, env): @@ -6,10 +7,10 @@ # From a wiki page if hdf: hdf['wiki.macro.greeting'] = 'Hello World' - + # args will be `None` if the macro is called without parenthesis. - args = txt or 'No arguments' + args = txt or 'Pas d\'argument' # then, as `txt` comes from the user, it's important to guard against # the possibility to inject malicious HTML/Javascript, by using `escape()`: - return 'Hello World, args = ' + escape(args) + return u'Bonjour tout le monde !! arguments = ' + escape(args) diff --exclude=.svn -Naur trac-0.10.4/wiki-macros/Timestamp.py trac-0.10.4-PKG/wiki-macros/Timestamp.py --- trac-0.10.4/wiki-macros/Timestamp.py 2007-04-20 15:41:43.000000000 +0200 +++ trac-0.10.4-PKG/wiki-macros/Timestamp.py 2007-08-24 12:31:18.000000000 +0200 @@ -1,4 +1,5 @@ -"""Inserts the current time (in seconds) into the wiki page.""" +# -*- coding: utf-8 -*- +u"""Insère la date actuelle (en secondes) sur la page Wiki.""" import time def execute(hdf, txt, env): diff --exclude=.svn -Naur trac-0.10.4/wiki-macros/TracGuideToc.py trac-0.10.4-PKG/wiki-macros/TracGuideToc.py --- trac-0.10.4/wiki-macros/TracGuideToc.py 2007-04-20 15:41:43.000000000 +0200 +++ trac-0.10.4-PKG/wiki-macros/TracGuideToc.py 2007-08-24 12:32:15.000000000 +0200 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- -""" -This macro shows a quick and dirty way to make a table-of-contents for a set -of wiki pages. +u""" +Cette macro affiche d'une façon simple et efficace la table des matières d'un ensemble de pages Wiki. """ TOC = [('TracGuide', 'Index'), @@ -29,7 +28,7 @@ def execute(hdf, args, env): html = '
    ' \ - '

    Table of Contents

    ' \ + '

    Sommaire

    ' \ '
      ' curpage = '%s' % hdf.getValue('wiki.page_name', '') lang, page = '/' in curpage and curpage.split('/', 1) or ('', curpage)

    - Completed ago () avant () - late en retard - Due in () - No date set

    %"> + if:#stats.total_tickets != #1 ?>s fermés"> + if:#stats.total_tickets != #1 ?>s ouverts">

    %

    -
    Closed tickets:
    +
    Tickets fermés :
    -
    Active tickets:
    +
    Tickets ouverts :
    - + - + - jalons, groupés par "> @@ -189,16 +195,18 @@
    + if:group.total_tickets != #1 ?>s fermés"> + if:group.total_tickets != 1 ?>s ouverts">
    @@ -219,7 +227,9 @@ if:milestone.id_param ?> - +