Hi folks,

I have an issue with concurrency & the dynamic updating of the
language files.
All works fine for a single user, however if multiple users are
accessing the site in a translated language then multiple attempts are
made to update the language file.

User can get an error traceback:
File "C:\Bin\web2py\gluon\languages.py", line 127, in __str__
    return self.T.translate(self.m, self.s)
  File "C:\Bin\web2py\gluon\languages.py", line 257, in translate
    write_dict(self.language_file, self.t)
  File "C:\Bin\web2py\gluon\languages.py", line 100, in write_dict
    fp.close()
IOError: [Errno 13] Permission denied

Then the language file loses all it's translations!
The file exists but all translated strings have reverted to the raw
untranslated version.

This is running current Web2Py trunk on both a Debian server (Python
2.5/WSGI) & a Windows 7 laptop (Python 2.6/Rocket).

I'm not sure why the file locking isn't working: portalocker.lock(fp,
portalocker.LOCK_EX)

A quick workaround is to set file permissisions to not allow the
webserver to update the file, which needs a patch to languages.py
(attached).
This patch is useful anyway as I never liked the fact that the system
would error out if the languages files weren't writable...this isn't a
failsafe behaviour.

This strikes me as the behaviour that we'd want on a Production
instance anyway since usually the translations will be happening
offline (e.g. using a collaborative Pootle instance) so merging in the
dynamic strings with the updated versions is a pain.

However, I do like the idea of capturing the missing strings from the
Production instance to get these merged offline into the master file,
so wonder whether it's worth writing these out to a separate file?
- this file being common to all languages as the missing strings
should be added to every file...

Best Wishes,
Fran.




--- languages.orig.py   Wed Sep 22 11:19:16 2010
+++ languages.py        Wed Sep 22 11:29:17 2010
@@ -31,7 +31,7 @@

 regex_translate = re.compile(PY_STRING_LITERAL_RE, re.DOTALL)

-# patter for a valid accept_language
+# pattern for a valid accept_language

 regex_language = \
     re.compile('^[a-zA-Z]{2}(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$')
@@ -90,6 +90,9 @@


 def write_dict(filename, contents):
+    if not os.access(filename, os.W_OK):
+        logging.error('Unable to write to file %s' % filename)
+        return
     fp = open(filename, 'w')
     portalocker.lock(fp, portalocker.LOCK_EX)
     fp.write('# coding: utf8\n{\n')

Reply via email to