DocumentationCodeBonnesPratiques » Historique » Version 27
Philippe Caseiro, 25/04/2014 11:32
1 | 20 | Daniel Dehennin | {{toc}} |
---|---|---|---|
2 | 20 | Daniel Dehennin | |
3 | 1 | Emmanuel GARETTE | h1. DocumentationCodeBonnesPratiques |
4 | 1 | Emmanuel GARETTE | |
5 | 18 | Gwenael Remond | **cette page concerne la documentation développeur** |
6 | 18 | Gwenael Remond | (voir aussi [[TestsCodeBonnesPratiques]] pour les autres bonnes pratiques développeur) |
7 | 18 | Gwenael Remond | |
8 | 1 | Emmanuel GARETTE | h2. Généralité |
9 | 1 | Emmanuel GARETTE | |
10 | 1 | Emmanuel GARETTE | * La documentation technique doit être en anglais. |
11 | 5 | Gérald Schwartzmann | * Elle est placée dans les docstrings du code. |
12 | 1 | Emmanuel GARETTE | |
13 | 1 | Emmanuel GARETTE | h2. Description du module |
14 | 1 | Emmanuel GARETTE | |
15 | 12 | Daniel Dehennin | La docstring du module est placée en haut du fichier juste après le "shebang":https://fr.wikipedia.org/wiki/Shebang, la déclaration d’"encodage des caractères":https://fr.wikipedia.org/wiki/Codage_de_caract%C3%A8res et la licence du code. |
16 | 2 | Gwenael Remond | |
17 | 1 | Emmanuel GARETTE | <pre> |
18 | 12 | Daniel Dehennin | #!/usr/bin/python |
19 | 12 | Daniel Dehennin | # -*- coding: utf-8 -*- |
20 | 12 | Daniel Dehennin | # |
21 | 16 | Emmanuel GARETTE | ########################################################################## |
22 | 16 | Emmanuel GARETTE | # <nom du projet> |
23 | 19 | Daniel Dehennin | # Copyright © 2013 Pôle de compétences EOLE <eole@ac-dijon.fr> |
24 | 14 | Daniel Dehennin | # |
25 | 16 | Emmanuel GARETTE | # License CeCILL: |
26 | 16 | Emmanuel GARETTE | # * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html |
27 | 16 | Emmanuel GARETTE | # * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html |
28 | 16 | Emmanuel GARETTE | ########################################################################## |
29 | 2 | Gwenael Remond | </pre> |
30 | 2 | Gwenael Remond | |
31 | 11 | Daniel Dehennin | La docstring doit contenir : |
32 | 1 | Emmanuel GARETTE | * description rapide en une phrase du module ; |
33 | 1 | Emmanuel GARETTE | * description avancée qui explique le rôle du module ; |
34 | 1 | Emmanuel GARETTE | * des exemples simples d'utilisation. |
35 | 1 | Emmanuel GARETTE | |
36 | 1 | Emmanuel GARETTE | Les exemples peuvent être un prompt : |
37 | 1 | Emmanuel GARETTE | |
38 | 1 | Emmanuel GARETTE | <pre> |
39 | 1 | Emmanuel GARETTE | >>> is_locked() |
40 | 1 | Emmanuel GARETTE | True |
41 | 1 | Emmanuel GARETTE | </pre> |
42 | 1 | Emmanuel GARETTE | |
43 | 1 | Emmanuel GARETTE | ou une portion de code : |
44 | 1 | Emmanuel GARETTE | |
45 | 1 | Emmanuel GARETTE | <pre> |
46 | 1 | Emmanuel GARETTE | :: |
47 | 1 | Emmanuel GARETTE | |
48 | 1 | Emmanuel GARETTE | from toto.titi import is_locked |
49 | 1 | Emmanuel GARETTE | |
50 | 1 | Emmanuel GARETTE | toto() |
51 | 1 | Emmanuel GARETTE | is_locked() |
52 | 1 | Emmanuel GARETTE | </pre> |
53 | 1 | Emmanuel GARETTE | |
54 | 1 | Emmanuel GARETTE | h2. Docstring des méthodes |
55 | 1 | Emmanuel GARETTE | |
56 | 3 | Gwenael Remond | Seules les méthodes publiques (qui ne commencent pas par "_") seront mises dans la documentation (mais les méthodes privées sont aussi à documenter). |
57 | 1 | Emmanuel GARETTE | |
58 | 1 | Emmanuel GARETTE | La docstring doit contenir : |
59 | 1 | Emmanuel GARETTE | |
60 | 1 | Emmanuel GARETTE | * description rapide en une phrase de la méthode ; |
61 | 1 | Emmanuel GARETTE | * si nécessaire une description avancée qui explique le rôle du module ; |
62 | 1 | Emmanuel GARETTE | * si nécessaire des exemples simples d'utilisation. |
63 | 1 | Emmanuel GARETTE | * les paramètres de la façon suivante (xxx étant le nom du paramètre et yyyyyy la description) : |
64 | 1 | Emmanuel GARETTE | |
65 | 1 | Emmanuel GARETTE | <pre> |
66 | 1 | Emmanuel GARETTE | :param xxx: yyyyyy |
67 | 1 | Emmanuel GARETTE | </pre> |
68 | 1 | Emmanuel GARETTE | |
69 | 1 | Emmanuel GARETTE | Si nécessaire les valeurs de retour (yyyyyy étant la description) : |
70 | 1 | Emmanuel GARETTE | |
71 | 1 | Emmanuel GARETTE | <pre> |
72 | 1 | Emmanuel GARETTE | :return: yyyyyy |
73 | 1 | Emmanuel GARETTE | </pre> |
74 | 1 | Emmanuel GARETTE | |
75 | 4 | Gwenael Remond | plus d'info sur la syntaxe des docstrings: http://sphinx-doc.org/domains.html#info-field-lists |
76 | 4 | Gwenael Remond | |
77 | 1 | Emmanuel GARETTE | h2. Docstring des classes |
78 | 1 | Emmanuel GARETTE | |
79 | 10 | Gwenael Remond | comme pour la docstring des modules (mais sans la licence) |
80 | 8 | Gwenael Remond | |
81 | 8 | Gwenael Remond | h2. Tips |
82 | 8 | Gwenael Remond | |
83 | 8 | Gwenael Remond | il est possible de faire un lien portant directement sur le redmine de deux manières : |
84 | 8 | Gwenael Remond | |
85 | 8 | Gwenael Remond | <pre> |
86 | 8 | Gwenael Remond | |
87 | 8 | Gwenael Remond | :issue:`410` |
88 | 8 | Gwenael Remond | |
89 | 8 | Gwenael Remond | </pre> |
90 | 8 | Gwenael Remond | |
91 | 8 | Gwenael Remond | est un lien qui porte directement sur la demande 410 |
92 | 8 | Gwenael Remond | |
93 | 8 | Gwenael Remond | et |
94 | 8 | Gwenael Remond | |
95 | 8 | Gwenael Remond | <pre> |
96 | 8 | Gwenael Remond | |
97 | 8 | Gwenael Remond | :eole:`/projects/creole/wiki/Lock24` |
98 | 8 | Gwenael Remond | |
99 | 8 | Gwenael Remond | </pre> |
100 | 8 | Gwenael Remond | |
101 | 8 | Gwenael Remond | qui est simplement un raccourci vers http://dev-eole.ac-dijon.fr/projects/creole/wiki/Lock24 |
102 | 17 | Daniel Dehennin | |
103 | 17 | Daniel Dehennin | h2. Exemples |
104 | 17 | Daniel Dehennin | |
105 | 17 | Daniel Dehennin | Plusieurs fichiers sources ont reçu une attention assez particulière sur la documentation : |
106 | 17 | Daniel Dehennin | |
107 | 17 | Daniel Dehennin | - python-pyeole:source:pyeole/decorator.py |
108 | 17 | Daniel Dehennin | - python-pyeole:source:pyeole/log.py |
109 | 17 | Daniel Dehennin | - python-pyeole:source:pyeole/lock.py |
110 | 21 | Philippe Caseiro | |
111 | 21 | Philippe Caseiro | h2. Traduction et python |
112 | 22 | Philippe Caseiro | |
113 | 24 | Philippe Caseiro | |
114 | 24 | Philippe Caseiro | |
115 | 22 | Philippe Caseiro | Voici un petit aide mémoire pour traduire une application python de la manière la plus simple possible. |
116 | 22 | Philippe Caseiro | |
117 | 26 | Philippe Caseiro | Pour traduire une application il faut en premier avant tout une bibliothèque qui gère les traductions, la première |
118 | 26 | Philippe Caseiro | qui viens à l'esprit est _gettext_, donc logiquement nous allons nous tourner vers _python-gettext_. |
119 | 22 | Philippe Caseiro | |
120 | 26 | Philippe Caseiro | Il faut noter qu'il est important de faire les choses dans l'ordre, les messages par défaut des applications doivent être dans *une seule et unique langue*, l'usage |
121 | 22 | Philippe Caseiro | est de tout écrire en anglais et ensuite de mettre une traduction pour les autres langues. |
122 | 22 | Philippe Caseiro | |
123 | 26 | Philippe Caseiro | Le principe de gettext est de remplacer tous les messages par l'appel à une "fonction/méthode/whatever" qui vas |
124 | 22 | Philippe Caseiro | faire les opérations de traduction. |
125 | 22 | Philippe Caseiro | |
126 | 26 | Philippe Caseiro | Dans le monde _gettext_ cette "fonction" a pour nom '_'. |
127 | 22 | Philippe Caseiro | |
128 | 26 | Philippe Caseiro | La première chose à faire est de mettre a disposition une "fonction" '_' dans votre application python. (Les exemples suivants proviennent de pyeole) |
129 | 22 | Philippe Caseiro | |
130 | 22 | Philippe Caseiro | h3. i18n.py |
131 | 22 | Philippe Caseiro | |
132 | 26 | Philippe Caseiro | On crée un "module" i18n.py (mais il pourrais très bien avoir un autre nom) et on y fait les déclarations et les initialisations nécessaires pour la traduction. |
133 | 22 | Philippe Caseiro | |
134 | 26 | Philippe Caseiro | * Dans ce module on importe gettext et les modules nécessaires à la gestion de la traduction (python-gettext) |
135 | 22 | Philippe Caseiro | <pre> |
136 | 22 | Philippe Caseiro | import gettext # Gettext lui même |
137 | 22 | Philippe Caseiro | import os # Pour les variables d'environement LANG/LC_ALL |
138 | 22 | Philippe Caseiro | import sys # Pour la gestion des fichiers de traduction |
139 | 22 | Philippe Caseiro | import locale # Pour la gestion des "locale" |
140 | 22 | Philippe Caseiro | </pre> |
141 | 22 | Philippe Caseiro | * On définis le nom du domaine de traduction (le plus souvent le nom de l'application) |
142 | 22 | Philippe Caseiro | <pre> |
143 | 22 | Philippe Caseiro | APP_NAME = 'pyeole' |
144 | 22 | Philippe Caseiro | </pre> |
145 | 22 | Philippe Caseiro | * On récupère les répertoires qui vont contentir les traductions |
146 | 22 | Philippe Caseiro | <pre> |
147 | 22 | Philippe Caseiro | # Traduction dir |
148 | 22 | Philippe Caseiro | APP_DIR = os.path.join(sys.prefix, 'share') |
149 | 22 | Philippe Caseiro | LOCALE_DIR = os.path.join(APP_DIR, 'locale') |
150 | 22 | Philippe Caseiro | </pre> |
151 | 22 | Philippe Caseiro | * On récupère la langue par défaut et on y ajoute l'anglais pour les messages non traduits |
152 | 23 | Philippe Caseiro | <pre> |
153 | 22 | Philippe Caseiro | # Default Lanugage |
154 | 22 | Philippe Caseiro | DEFAULT_LANG = os.environ.get('LANG', '').split(':') |
155 | 1 | Emmanuel GARETTE | DEFAULT_LANG += ['en_US'] |
156 | 23 | Philippe Caseiro | </pre> |
157 | 23 | Philippe Caseiro | * On définis la langue par défaut (je ne suis pas certain que cette partie ne soit pas inutile :) |
158 | 23 | Philippe Caseiro | <pre> |
159 | 22 | Philippe Caseiro | languages = [] |
160 | 22 | Philippe Caseiro | lc, encoding = locale.getdefaultlocale() |
161 | 22 | Philippe Caseiro | if lc: |
162 | 22 | Philippe Caseiro | languages = [lc] |
163 | 1 | Emmanuel GARETTE | |
164 | 1 | Emmanuel GARETTE | languages += DEFAULT_LANG |
165 | 23 | Philippe Caseiro | </pre> |
166 | 23 | Philippe Caseiro | * On fait les initialisations gettext |
167 | 23 | Philippe Caseiro | <pre> |
168 | 1 | Emmanuel GARETTE | mo_location = LOCALE_DIR |
169 | 1 | Emmanuel GARETTE | |
170 | 23 | Philippe Caseiro | gettext.find(APP_NAME, mo_location) # On cherche les traductions |
171 | 23 | Philippe Caseiro | gettext.textdomain(APP_NAME) # On crée le domaine de traduction (ou il vas chercher les messages) |
172 | 23 | Philippe Caseiro | gettext.bind_textdomain_codeset(APP_NAME, "UTF-8") # On définis le jeux de caracètres des traductions (utf8) |
173 | 23 | Philippe Caseiro | </pre> |
174 | 23 | Philippe Caseiro | * On initialise l'objet qui vas réaliser les traductions pour notre application |
175 | 23 | Philippe Caseiro | <pre> |
176 | 22 | Philippe Caseiro | t = gettext.translation(APP_NAME, fallback=True) |
177 | 23 | Philippe Caseiro | </pre> |
178 | 23 | Philippe Caseiro | * Enfin on créer la "fonction/methode/whatever" '_' : |
179 | 23 | Philippe Caseiro | <pre> |
180 | 1 | Emmanuel GARETTE | def _(msg): |
181 | 23 | Philippe Caseiro | return t.ugettext(msg) # on retourne le résultat de la traduction ! ugettext peut poser problème il ne prend que des chaines utf8 |
182 | 1 | Emmanuel GARETTE | </pre> |
183 | 24 | Philippe Caseiro | |
184 | 24 | Philippe Caseiro | Vous n'avez plus qu'a importer la "fonction/méthode" '_' dans vos fichier .py et l'utiliser |
185 | 24 | Philippe Caseiro | |
186 | 24 | Philippe Caseiro | Exemple : |
187 | 24 | Philippe Caseiro | <pre> |
188 | 24 | Philippe Caseiro | from pyeole.translation.i18n import _ # j'ai mis le module i18n.py dans un répertoire spécifique (pour le plaisir) |
189 | 24 | Philippe Caseiro | |
190 | 24 | Philippe Caseiro | .... |
191 | 24 | Philippe Caseiro | |
192 | 24 | Philippe Caseiro | msg = _(u'Install: {0}.') |
193 | 24 | Philippe Caseiro | log.info(msg.format(u', '.join(to_install))) |
194 | 24 | Philippe Caseiro | </pre> |
195 | 24 | Philippe Caseiro | |
196 | 24 | Philippe Caseiro | h3. let's translate |
197 | 24 | Philippe Caseiro | |
198 | 27 | Philippe Caseiro | Une fois le code en place il faut créer les fichiers de traduction. Il existe plusieurs utilitaires pour faire de la traduction, personnellement j'utilise "poedit" (ou vim :) |
199 | 24 | Philippe Caseiro | |
200 | 27 | Philippe Caseiro | Il faut générer le fichier de référence des messages, pour ce faire on utilise la commande _xgettext_. |
201 | 1 | Emmanuel GARETTE | |
202 | 27 | Philippe Caseiro | On place les fichiers de traductions dans un répertoire *translation* à la racine du dépôt. |
203 | 27 | Philippe Caseiro | |
204 | 1 | Emmanuel GARETTE | <pre> |
205 | 27 | Philippe Caseiro | dev@dev-machine:~ $ cd code/pyeole |
206 | 27 | Philippe Caseiro | dev@dev-machine:~/code/pyeole $ # mkdir translation |
207 | 27 | Philippe Caseiro | dev@dev-machine:~/code/pyeole cd translation |
208 | 27 | Philippe Caseiro | dev@dev-machine:~/code/pyeole/translation # xgettext --language=Python --keyword=_ --output=pyeole-next.pot --from-code=UTF-8 `find ../pyeole -name "*.py"` |
209 | 24 | Philippe Caseiro | </pre> |
210 | 24 | Philippe Caseiro | |
211 | 27 | Philippe Caseiro | Attention il est possible que _xgettext_ plante a cause de certaines chaines de commentaire. |
212 | 24 | Philippe Caseiro | |
213 | 27 | Philippe Caseiro | Une fois que la commande _xgettext_ ce termine elle génère un fichier ".pot" |
214 | 24 | Philippe Caseiro | |
215 | 24 | Philippe Caseiro | Pour générer les traductions on utilise poedit. |
216 | 24 | Philippe Caseiro | |
217 | 24 | Philippe Caseiro | # Lancer poedit |
218 | 24 | Philippe Caseiro | # Fichier --> Nouveau depuis un fichier POT/PO |
219 | 24 | Philippe Caseiro | # Ouvrir votre fichier .pot |
220 | 24 | Philippe Caseiro | # Séléctionner la langue de traduction |
221 | 24 | Philippe Caseiro | # Traduire les chaines disponibles |
222 | 24 | Philippe Caseiro | # Sauvegarder le fichier de traduction dans le répertoire translation/<CODE_LANGUE>/<mon_appli>.po (translation/fr/pyeole.po) |
223 | 24 | Philippe Caseiro | |
224 | 24 | Philippe Caseiro | h3. plus qu'a installer |
225 | 25 | Philippe Caseiro | |
226 | 25 | Philippe Caseiro | Pour que les fichiers de traductions soit pris en compte par la génération du paquet il faut faire des mise à jour dans le setup.py. |
227 | 25 | Philippe Caseiro | |
228 | 25 | Philippe Caseiro | On créer ajoute une petite fonction qui vas créer les fichier de traduction a partir des .po et oui les .po ne sont pas les fichiers |
229 | 25 | Philippe Caseiro | utilisés par gettext mais juste leur "code source". Il faut impérativement que la traduction soit la plus rapide possible donc qui dit |
230 | 25 | Philippe Caseiro | rapide dit fichiers binaires. |
231 | 25 | Philippe Caseiro | |
232 | 25 | Philippe Caseiro | Voici le code qui gènère les .mo |
233 | 25 | Philippe Caseiro | |
234 | 25 | Philippe Caseiro | <pre> |
235 | 25 | Philippe Caseiro | trad_root = "share/locale" |
236 | 25 | Philippe Caseiro | trad_dir = "LC_MESSAGES" |
237 | 25 | Philippe Caseiro | here = dirname(abspath(__file__)) |
238 | 25 | Philippe Caseiro | |
239 | 25 | Philippe Caseiro | def build_translation(): |
240 | 25 | Philippe Caseiro | po_path = join(here, "translation") |
241 | 25 | Philippe Caseiro | result = [] |
242 | 25 | Philippe Caseiro | |
243 | 25 | Philippe Caseiro | for top, dirs, files in walk(po_path): |
244 | 25 | Philippe Caseiro | for directory in dirs: |
245 | 25 | Philippe Caseiro | tr_dir = join(top, directory) |
246 | 25 | Philippe Caseiro | # Search for .po file for a traduction |
247 | 25 | Philippe Caseiro | trad_files = [] |
248 | 25 | Philippe Caseiro | for pot_file in glob(join(tr_dir, "*.po")): |
249 | 25 | Philippe Caseiro | mo_file = splitext(pot_file)[0] + ".mo" |
250 | 25 | Philippe Caseiro | lang = basename(tr_dir) |
251 | 25 | Philippe Caseiro | cmd = ["msgfmt", pot_file, "-o", mo_file] |
252 | 25 | Philippe Caseiro | dest = join(trad_root, lang, trad_dir) |
253 | 25 | Philippe Caseiro | trad_files.append(join("translation", lang, basename(mo_file))) |
254 | 25 | Philippe Caseiro | call(cmd) |
255 | 25 | Philippe Caseiro | result.append((dest, trad_files)) |
256 | 25 | Philippe Caseiro | |
257 | 25 | Philippe Caseiro | return result |
258 | 25 | Philippe Caseiro | |
259 | 25 | Philippe Caseiro | translations = build_translation() |
260 | 25 | Philippe Caseiro | </pre> |
261 | 25 | Philippe Caseiro | |
262 | 25 | Philippe Caseiro | Voici les directives supplémentaires pour la fonction setup() |
263 | 25 | Philippe Caseiro | |
264 | 25 | Philippe Caseiro | <pre> |
265 | 25 | Philippe Caseiro | data_files = translations |
266 | 25 | Philippe Caseiro | <pre> |
267 | 25 | Philippe Caseiro | |
268 | 25 | Philippe Caseiro | |
269 | 25 | Philippe Caseiro | h2. Des questions ? |
270 | 25 | Philippe Caseiro | |
271 | 25 | Philippe Caseiro | Voila une fois que vous avez fait toutes ces opérations votre appli doit parler d'autres langues. |
272 | 24 | Philippe Caseiro | |
273 | 1 | Emmanuel GARETTE | Si vous avez des questions cette partie à été écrite par Philippe "Puppet_Master" Caseiro. |