Merge lp:~graeme-acm/sahana-eden/RMS into lp:sahana-eden

Proposed by Graeme Foster
Status: Merged
Merged at revision: 2954
Proposed branch: lp:~graeme-acm/sahana-eden/RMS
Merge into: lp:sahana-eden
Diff against target: 589 lines (+233/-43)
3 files modified
controllers/survey.py (+101/-30)
models/survey.py (+100/-5)
modules/s3/s3survey.py (+32/-8)
To merge this branch: bzr merge lp:~graeme-acm/sahana-eden/RMS
Reviewer Review Type Date Requested Status
Fran Boon Pending
Review via email: mp+83409@code.launchpad.net

Description of the change

Finishing off the spreadsheet translation

ticket #1042

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'controllers/survey.py'
2--- controllers/survey.py 2011-11-23 10:48:23 +0000
3+++ controllers/survey.py 2011-11-25 15:29:24 +0000
4@@ -28,13 +28,15 @@
5
6 from gluon.contenttype import contenttype
7 from gluon.serializers import json
8+from gluon.languages import read_dict, write_dict
9
10 from s3survey import S3AnalysisPriority, \
11 survey_question_type, \
12 survey_analysis_type, \
13 S3Chart, \
14 DataMatrix, MatrixElement, \
15- S3QuestionTypeOptionWidget
16+ S3QuestionTypeOptionWidget, \
17+ survey_T
18
19 module = request.controller
20 prefix = request.controller
21@@ -66,8 +68,18 @@
22 def prep(r):
23 if r.component and r.component_name == "translate":
24 table = db["survey_translate"]
25- table.file.readable = False
26- table.file.writable = False
27+ # list existing translations and allow the addition of a new translation
28+ if r.component_id == None:
29+ table.file.readable = False
30+ table.file.writable = False
31+ # edit the selected translation
32+ else:
33+ table.language.writable = False
34+ table.code.writable = False
35+ # remove CRUD generated buttons in the tabs
36+ s3mgr.configure(table,
37+ deletable=False,
38+ )
39 else:
40 s3_action_buttons(r)
41 query = (r.table.status == 1) # Status of Pending
42@@ -88,8 +100,8 @@
43 # Post-processor
44 def postp(r, output):
45 if r.component:
46+ template_id = request.args[0]
47 if r.component_name == "section":
48- template_id = request.args[0]
49 # Add the section select widget to the form
50 sectionSelect = response.s3.survey_section_select_widget(template_id)
51 output.update(form = sectionSelect)
52@@ -101,9 +113,18 @@
53 _class="action-btn",
54 url=URL(c=module,
55 f="templateTranslateDownload",
56- args=["[id]","update"])
57- ),
58- )
59+ args=["[id]"])
60+ ),
61+ )
62+ response.s3.actions.append(
63+ dict(label=str(T("Upload")),
64+ _class="action-btn",
65+ url=URL(c=module,
66+ f="template",
67+ args=[template_id,"translate","[id]"])
68+ ),
69+ )
70+ return output
71
72
73 # Add a button to show what the questionnaire looks like
74@@ -147,16 +168,15 @@
75
76 response.s3.prep = prep
77
78- # remove CRUD generated buttons in the tabs
79- s3mgr.configure(tablename,
80- listadd=False,
81- deletable=False,
82- )
83-
84 response.s3.postp = postp
85 rheader = response.s3.survey_template_rheader
86+ # remove CRUD generated buttons in the tabs
87+ s3mgr.configure(tablename,
88+ listadd=False,
89+ deletable=False,
90+ )
91 output = s3_rest_controller(prefix, resourcename, rheader=rheader)
92-
93+
94 return output
95
96 def templateRead():
97@@ -249,15 +269,24 @@
98 redirect(URL(c="survey",
99 f="templateTranslation",
100 args=[],
101- vars = {}))
102+ vars = {}))
103 code = record.code
104 language = record.language
105+ lang_fileName = "applications/%s/languages/%s.py" % (request.application, code)
106+ try:
107+ strings = read_dict(lang_fileName)
108+ except:
109+ strings = dict()
110 template_id = record.template_id
111+ template = response.s3.survey_getTemplate(template_id)
112 book = xlwt.Workbook(encoding="utf-8")
113 sheet = book.add_sheet(language)
114 output = StringIO()
115 qstnList = response.s3.survey_getAllQuestionsForTemplate(template_id)
116 original = {}
117+ original[template["name"]] = True
118+ if template["description"] != "":
119+ original[template["description"]] = True
120 for qstn in qstnList:
121 original[qstn["name"]] = True
122 widgetObj = survey_question_type[qstn["type"]](question_id = qstn["qstn_id"])
123@@ -267,6 +296,7 @@
124 original[option] = True
125 sections = response.s3.survey_getAllSectionsForTemplate(template_id)
126 for section in sections:
127+ original[section["name"]]=True
128 section_id = section["section_id"]
129 layoutRules = response.s3.survey_getQstnLayoutRules(template_id, section_id)
130 layoutStr = str(layoutRules)
131@@ -290,10 +320,16 @@
132 originalList.sort()
133 for text in originalList:
134 row += 1
135+ original = unicode(text)
136 sheet.write(row,
137 0,
138- unicode(text)
139+ original
140 )
141+ if (original in strings):
142+ sheet.write(row,
143+ 1,
144+ strings[original]
145+ )
146
147 book.save(output)
148 output.seek(0)
149@@ -312,6 +348,14 @@
150
151 def prep(r):
152 if r.interactive:
153+ if r.method == "create":
154+ allTemplates = response.s3.survey_getAllTemplates()
155+ if len(allTemplates) == 0:
156+ session.warning = T("You need to create a template before you can create a series")
157+ redirect(URL(c="survey",
158+ f="template",
159+ args=[],
160+ vars = {}))
161 if r.id and (r.method == "update"):
162 table.template_id.writable = False
163 return True
164@@ -347,13 +391,6 @@
165 s3mgr.load(tablename)
166 crud_strings = response.s3.crud_strings[tablename]
167
168- # Check that the series_id has been passed in
169- if len(request.args) != 1:
170- output = s3_rest_controller(prefix,
171- resourcename,
172- rheader=response.s3.survey_series_rheader)
173- return output
174-
175 try:
176 import xlwt
177 except ImportError:
178@@ -369,6 +406,22 @@
179 # * The sections within the template
180 # * The layout rules for each question
181 ######################################################################
182+ # Check that the series_id has been passed in
183+ if len(request.args) != 1:
184+ output = s3_rest_controller(prefix,
185+ resourcename,
186+ rheader=response.s3.survey_series_rheader)
187+ return output
188+ if "translationLanguage" in current.request.post_vars:
189+ lang = current.request.post_vars.translationLanguage
190+ if lang == "Default":
191+ langDict = dict()
192+ else:
193+ try:
194+ lang_fileName = "applications/%s/languages/%s.py" % (request.application, lang)
195+ langDict = read_dict(lang_fileName)
196+ except:
197+ langDict = dict()
198 series_id = request.args[0]
199 sectionList = response.s3.survey_getAllSectionsForSeries(series_id)
200 layout = {}
201@@ -463,7 +516,8 @@
202 (endrow, endcol) = widgetObj.writeToMatrix(matrix,
203 row,
204 col,
205- answerMatrix=matrixAnswer
206+ answerMatrix=matrixAnswer,
207+ langDict = langDict
208 )
209 except Exception as msg:
210 print msg
211@@ -492,7 +546,7 @@
212 row += 1
213 else:
214 logo = None
215- title = template.description
216+ title = survey_T(template.description, langDict)
217 cell = MatrixElement(0,col,title, style="styleHeader")
218 cell.merge(vertical=1, horizontal=4)
219 matrix.addElement(cell)
220@@ -502,7 +556,7 @@
221 col = 0
222 row += 1
223 rules = layout[section["name"]]
224- cell = MatrixElement(row,col,section["name"], style="styleHeader")
225+ cell = MatrixElement(row,col,survey_T(section["name"],langDict), style="styleHeader")
226 try:
227 matrix.addElement(cell)
228 except Exception as msg:
229@@ -952,6 +1006,7 @@
230
231 def postp(r, output):
232 if r.interactive:
233+ T = current.T
234 if "viewing" in current.request.vars:
235 dummy, series_id = current.request.vars.viewing.split(".")
236 elif "series" in current.request.vars:
237@@ -966,20 +1021,36 @@
238 vars = {}))
239 response.s3.survey_answerlist_dataTable_post(r)
240 form = response.s3.survey_buildQuestionnaireFromSeries(series_id, None)
241+ translationList = response.s3.survey_getAllTranslationsForSeries(series_id)
242 urlexport = URL(c=module,
243 f="series_export_formatted",
244 args=[series_id]
245 )
246+ tranForm = FORM(_action=urlexport)
247+ tranForm.append(INPUT(_type='checkbox',
248+ _name='translationLanguage',
249+ _value="Default",
250+ value=True,
251+ ))
252+ tranForm.append(LABEL("Default"))
253+ for translation in translationList:
254+ tranForm.append(INPUT(_type='checkbox',
255+ _name='translationLanguage',
256+ _value=translation["code"],
257+ ))
258+ tranForm.append(LABEL(translation["language"]))
259+ exportBtn = INPUT(_type="submit", _id="export_btn", _name="Export_Spreadsheet", _value=T("Export Assessment as a Formatted Spreadsheet"))
260+ tranForm.append(exportBtn)
261 urlimport = URL(c=module,
262 f="complete",
263 args=[series_id,"import.xml"],
264 vars = {"extra_data":True}
265 )
266- T = current.T
267- buttons = DIV (A(T("Export Assessment as a Formatted Spreadsheet"), _href=urlexport, _id="Excel-export", _class="action-btn"),
268+ buttons = DIV (#A(T("Export Assessment as a Formatted Spreadsheet"), _href=urlexport, _id="Excel-export", _class="action-btn"),
269 A(T("Import Spreadsheet as an Assessment"), _href=urlimport, _id="Excel-import", _class="action-btn"),
270 )
271- output["subtitle"] = buttons
272+ tranForm.append(buttons)
273+ output["subtitle"] = tranForm
274 output["form"] = form
275 return output
276
277@@ -1032,7 +1103,7 @@
278 except ImportError:
279 print >> sys.stderr, "ERROR: xlrd & xlwt modules are needed for importing spreadsheets"
280 return None
281- workbook = xlrd.open_workbook(filename=uploadFile)
282+ workbook = xlrd.open_workbook(filename=uploadFile.file)
283 sheetR = workbook.sheet_by_name("Assessment")
284 sheetM = workbook.sheet_by_name("Metadata")
285 header = '"Series"'
286
287=== modified file 'models/survey.py'
288--- models/survey.py 2011-11-23 13:40:47 +0000
289+++ models/survey.py 2011-11-25 15:29:24 +0000
290@@ -27,6 +27,8 @@
291 import json
292 sys.path.append("applications/%s/modules/s3" % request.application)
293
294+ from gluon.languages import read_dict, write_dict
295+
296 from s3codec import S3Codec
297 from xml.sax.saxutils import unescape
298 from s3survey import survey_question_type, \
299@@ -1334,9 +1336,71 @@
300 s3.crud_strings[tablename] = Storage(
301 title_create = T("Add new translation language"),
302 )
303+
304+ def translate_onaccept(form):
305+ """
306+ If the translation spreadsheet has been uploaded then
307+ it needs to be processed.
308+
309+ The translation strings need to be extracted from
310+ the spreadsheet and inserted into the language file.
311+ """
312+ if "file" in form.vars:
313+ try:
314+ import xlrd
315+ except ImportError:
316+ print >> sys.stderr, "ERROR: xlrd & xlwt modules are needed for importing spreadsheets"
317+ return None
318+
319+ msgNone = T("No translations exist in spreadsheet")
320+ upload_file = current.request.post_vars.file
321+ upload_file.file.seek(0)
322+ openFile = upload_file.file.read()
323+ lang = form.record.language
324+ code = form.record.code
325+ try:
326+ workbook = xlrd.open_workbook(file_contents=openFile)
327+ except:
328+ msg = T("Unable to open spreadsheet")
329+ current.response.error = msg
330+ current.response.flash = None
331+ return
332+ try:
333+ sheetL = workbook.sheet_by_name(lang)
334+ except:
335+ msg = T("Unable to find sheet %(sheet_name)s in uploaded spreadsheet") % dict(sheet_name=lang)
336+ current.response.error = msg
337+ current.response.flash = None
338+ return
339+ if sheetL.ncols == 1:
340+ current.response.warning = msgNone
341+ current.response.flash = None
342+ return
343+ count = 0
344+ lang_fileName = "applications/%s/languages/%s.py" % (request.application, code)
345+ try:
346+ strings = read_dict(lang_fileName)
347+ except:
348+ strings = dict()
349+ for row in xrange(1, sheetL.nrows):
350+ original = sheetL.cell_value(row, 0)
351+ translation = sheetL.cell_value(row, 1)
352+ if (original not in strings) or translation != "":
353+ strings[original] = translation
354+ count += 1
355+ write_dict(lang_fileName, strings)
356+ if count == 0:
357+ current.response.warning = msgNone
358+ current.response.flash = None
359+ else:
360+ current.response.flash = T("%(count_of)d translations have been imported to the %(language)s language file") % dict(count_of=count, language=lang)
361+
362 # components
363 s3mgr.model.add_component("survey_translate",
364 survey_template="template_id")
365+ s3mgr.configure(tablename,
366+ onaccept = translate_onaccept,
367+ )
368 #**********************************************************************
369 # The bread and butter methods to get data off the database
370 #**********************************************************************
371@@ -1390,6 +1454,14 @@
372 #**********************************************************************
373 # Functions to get a list of records from the database
374 #**********************************************************************
375+ def getAllTemplates():
376+ """
377+ function to return all the templates on the database
378+ """
379+ table = db.survey_template
380+ row = db(table).select()
381+ return row
382+
383 def getAllSeries():
384 """
385 function to return all the series on the database
386@@ -1398,6 +1470,22 @@
387 row = db(table).select()
388 return row
389
390+ def getAllTranslationsForTemplate(template_id):
391+ """
392+ function to return all the translations for the given template
393+ """
394+ table = db.survey_translate
395+ row = db(table).select()
396+ return row
397+
398+ def getAllTranslationsForSeries(series_id):
399+ """
400+ function to return all the translations for the given series
401+ """
402+ row = getSeries(series_id)
403+ template_id = row.template_id
404+ return getAllTranslationsForTemplate(template_id)
405+
406 def getAllQuestionsForTemplate(template_id):
407 """
408 function to return the list of questions for the given template
409@@ -1604,9 +1692,11 @@
410 tabs = [(T("Basic Details"), "read"),
411 (T("Question Details"),"templateRead/"),
412 (T("Question Summary"),"templateSummary/"),
413- (T("Translate"),"translate"),
414 # (T("Sections"), "section"),
415 ]
416+ if auth.s3_has_permission("create", "survey_translate"):
417+ tabs.append((T("Translate"),"translate"))
418+
419 rheader_tabs = s3_rheader_tabs(r, tabs)
420
421 sectionTable = db["survey_section"]
422@@ -2322,10 +2412,14 @@
423
424 return_dict = dict(
425 survey_updateMetaData = updateMetaData,
426+ survey_getTemplate = getTemplate,
427 survey_getTemplateFromSeries = getTemplateFromSeries,
428 survey_getSeries = getSeries,
429 survey_getSeriesName = getSeriesName,
430 survey_getTranslation = getTranslation,
431+ survey_getAllTranslationsForTemplate = getAllTranslationsForTemplate,
432+ survey_getAllTranslationsForSeries = getAllTranslationsForSeries,
433+ survey_getAllTemplates = getAllTemplates,
434 survey_getAllSeries = getAllSeries,
435 survey_getAllSectionsForTemplate = getAllSectionsForTemplate,
436 survey_getAllSectionsForSeries = getAllSectionsForSeries,
437@@ -2411,8 +2505,9 @@
438 If the record is a duplicate then it will set the job method to update
439
440 Rules for finding a duplicate:
441- - Look for a record with the same name, ignoring case
442- - and the same template
443+ - Look for a record with the same name
444+ - the same template
445+ - and the same position within the template
446 """
447 # ignore this processing if the id is set
448 if job.id:
449@@ -2420,9 +2515,9 @@
450 if job.tablename == "survey_section":
451 table = job.table
452 name = "name" in job.data and job.data.name
453+ posn = "posn" in job.data and job.data.posn
454 template = "template" in job.data and job.data.template_id
455-
456- query = table.name.lower().like('%%%s%%' % name.lower())
457+ query = ((table.name==name) & (table.template_id==template) & (table.posn==posn))
458 _duplicate = db(query).select(table.id, limitby=(0, 1)).first()
459 if _duplicate:
460 job.id = _duplicate.id
461
462=== modified file 'modules/s3/s3survey.py'
463--- modules/s3/s3survey.py 2011-11-23 13:42:20 +0000
464+++ modules/s3/s3survey.py 2011-11-25 15:29:24 +0000
465@@ -251,6 +251,15 @@
466 return S3QuestionTypeGridWidget(question_id)
467 def survey_gridChildType(question_id = None):
468 return S3QuestionTypeGridChildWidget(question_id)
469+def survey_T(phrase, langDict):
470+ """
471+ Function to translate a phrase using the dictionary passed in
472+ """
473+ if phrase in langDict and langDict[phrase] != "":
474+ return langDict[phrase]
475+ else:
476+ return phrase
477+
478
479 survey_question_type = {
480 "String": survey_stringType,
481@@ -493,10 +502,17 @@
482 """
483 return DIV(self.typeDescription, _class="surveyWidgetType")
484
485+ def _Tquestion(self, langDict):
486+ """
487+ Function to translate the question using the dictionary passed in
488+ """
489+ return survey_T(self.question["name"], langDict)
490+
491 def writeToMatrix(self,
492 matrix,
493 row,
494 col,
495+ langDict=dict(),
496 answerMatrix=None,
497 style={"Label": True
498 ,"LabelLeft" : True
499@@ -507,7 +523,7 @@
500 """
501 self._store_metadata()
502 if "Label" in style and style["Label"]:
503- cell = MatrixElement(row,col,self.question["name"], style="styleSubHeader")
504+ cell = MatrixElement(row,col,self._Tquestion(langDict), style="styleSubHeader")
505 matrix.addElement(cell)
506 if "LabelLeft" in style and style["LabelLeft"]:
507 col += 1
508@@ -867,6 +883,7 @@
509 matrix,
510 row,
511 col,
512+ langDict=dict(),
513 answerMatrix=None,
514 style={"Label": True
515 ,"LabelLeft" : False
516@@ -877,7 +894,7 @@
517 """
518 self._store_metadata()
519 if "Label" in style and style["Label"]:
520- cell = MatrixElement(row,col,self.question["name"], style="styleSubHeader")
521+ cell = MatrixElement(row,col,self._Tquestion(langDict), style="styleSubHeader")
522 matrix.addElement(cell)
523 if "LabelLeft" in style and style["LabelLeft"]:
524 col += 1
525@@ -895,7 +912,7 @@
526 answerMatrix.addElement(cell)
527 answerCol = 3
528 for option in list:
529- cell = MatrixElement(row,col,option, style="styleText")
530+ cell = MatrixElement(row,col,survey_T(option, langDict), style="styleText")
531 matrix.addElement(cell)
532 cell = MatrixElement(row,col+1,"", style="styleInput")
533 matrix.addElement(cell)
534@@ -1327,6 +1344,7 @@
535 matrix,
536 row,
537 col,
538+ langDict=dict(),
539 answerMatrix=None,
540 style={"Label": True
541 ,"LabelLeft" : True
542@@ -1343,7 +1361,7 @@
543 gridStyle = style
544 gridStyle["Label"] = False
545 if self.data != None:
546- cell = MatrixElement(row,col,self.subtitle, style="styleSubHeader")
547+ cell = MatrixElement(row,col,survey_T(self.subtitle, langDict), style="styleSubHeader")
548 matrix.addElement(cell)
549 # Add a *mostly* blank line for the heading.
550 # This will be added on the first run through the list
551@@ -1356,12 +1374,12 @@
552 for line in self.data:
553 col = startcol
554 row = nextrow
555- cell = MatrixElement(row,col,self.rows[posn], style="styleText")
556+ cell = MatrixElement(row,col,survey_T(self.rows[posn], langDict), style="styleText")
557 matrix.addElement(cell)
558 col += 1
559 for cell in line:
560 if firstRun:
561- cell = MatrixElement(row-1,col,self.columns[colCnt], style="styleSubHeader")
562+ cell = MatrixElement(row-1,col,survey_T(self.columns[colCnt], langDict), style="styleSubHeader")
563 matrix.addElement(cell)
564 colCnt += 1
565 if cell == "Blank":
566@@ -1372,7 +1390,12 @@
567 childWidget = self.getChildWidget(code)
568 type = childWidget.get("Type")
569 realWidget = survey_question_type[type](childWidget.id)
570- (endrow, col) = realWidget.writeToMatrix(matrix, row, col, answerMatrix, style)
571+ (endrow, col) = realWidget.writeToMatrix(matrix,
572+ row,
573+ col,
574+ langDict,
575+ answerMatrix,
576+ style)
577 if endrow > nextrow:
578 nextrow = endrow
579 posn += 1
580@@ -1501,7 +1524,8 @@
581 def writeToMatrix(self,
582 matrix,
583 row,
584- col,
585+ col,
586+ langDict=dict(),
587 answerMatrix=None,
588 style={}
589 ):