Alexandre Bourget

geek joy

Pyramid and Mako: how to do i18n the Pylons way

January 13, 2011 at 09:07 PM

In reply to this post about the Pylons way to do translation using Pyramid, here is my code snippet so that you don't need to put the request object in, each time you want to translate something:

__init__.py:

def main(...):
    ...
    config.add_subscriber('YOURPROJECT.subscribers.add_renderer_globals',
                          'pyramid.events.BeforeRender')
    config.add_subscriber('YOURPROJECT.subscribers.add_localizer',
                          'pyramid.events.NewRequest')

or wherever the following add_renderer_globals will be.

Then add, let's say in subscribers.py:

from pyramid.i18n import get_localizer, TranslationStringFactory

def add_renderer_globals(event):
    ...
    request = event.request
    event['_'] = request.translate
    event['localizer'] = request.localizer
    ...

tsf = TranslationStringFactory('YOUR_GETTEXT_DOMAIN')

def add_localizer(event):
    request = event.request
    localizer = get_localizer(request)
    def auto_translate(string):
        return localizer.translate(tsf(string))
    request.localizer = localizer
    request.translate = auto_translate

Now, in your Mako template, you'll be able to use the simple ${_(u"Translate this string please")} without having to specify the request explicitly, as it's enclosed in this request's "_" function. localizer will also be available for plural forms and fancy stuff.

This version will also allow you to use translation in your view code, using something like:

def my_view(request):
    _ = request.translate
    request.session.flash(_("Welcome home"))
    ...

Now for all that to work, you'll need to:

(env)$ pip install Babel

first, and also run these commands in your project's directory:

(env)$ python setup.py extract_messages
(env)$ python setup.py init_catalog -l en
(env)$ python setup.py init_catalog -l fr
(env)$ python setup.py init_catalog -l es
(env)$ python setup.py init_catalog -l it
(env)$ python setup.py update_catalog
(env)$ python setup.py compile_catalog

... for the langauges you need. Note that the sub-directory of your project is locale/ in Pyramid, and not i18n/ as it was in Pylons. You'll notice that in the default setup.cfg of a Pyramid project.

Lastly, you'll want to have your Mako files extracted when you run extract_messages, so add these to your setup.py (yes, you read me right, in setup.py so that Babel can use it when invoking it's commands):

python setup.py 
setup(
    ...
    install_requires=[
        ...
        Babel,
        ...
        ],
    message_extractors = {'yourpackage': [
            ('**.py', 'python', None),
            ('templates/**.html', 'mako', None),
            ('templates/**.mako', 'mako', None),
            ('static/**', 'ignore', None)]},
    ...
    )

Hope this helps.

UPDATED Jan 14th, 00:56: Added support for in-view translation.

Read and Post Comments

My new Blogofile blog

January 11, 2011 at 05:30 PM

Hello all.

With every New Year comes new resolutions, and mine was to revamp my blog. So here it is, shining new, and all with flat files. It's computed using the awesome little blogging engine called Blogofile. It's updated using Emacs and git, with a hook that automatically rebuilds every file from source files and Mako templates.

I migrated from a Zine blog which was leaking to death (probably due to a bad/weird paster setup of mine). The whole operation took about 5 hours, including the migration of my 20 other blog posts.

It uses the Disqus commenting system so it really doesn't need anything dynamic on the server side.

If things are wrong or have changed in an unexpected way, please leave a comment below. Thanks

Read and Post Comments

Geben + Emacs + Ubuntu, and Make the debugging work

September 13, 2010 at 09:55 AM

Geben is a neat piece of debugging tool for Emacs, which allows to remotely debug your applications.

I found that neat page that gives a quick how-to install Geben to debug PHP (xdebug) / Python apps.. but it doesn't close the loop.

Here's what you'll need to wire-in your emacs installation to have it actually work:

Add this to your ~/.emacs file:

(add-to-list 'load-path "/usr/share/emacs/23.1/site-lisp/geben") ; Geben directory
; Optionally load it on every run (only the library, won't run the server automatically)
(require 'geben)

If you haven't loaded it with require, then you'll need to run this in your emacs session:

M-x load-library geben

That is ESC and then 'x' on my machine, then type load-library in the bottom box, then it'll ask the library to load, and enter geben

The moment you want to start debugging, run M-x geben, and Emacs will start listening on port 9000 for incoming connections from your debugging server

To discover the shortcuts, in emacs, run C-h b and look at the Geben minor mode key bindings.

Here's a quick glance:

SPC             geben-step-again
>               geben-set-redirect
?               geben-mode-help
B               geben-breakpoint-menu
U               geben-clear-breakpoints
b               geben-set-breakpoint-line
c               geben-run-to-cursor
d               geben-show-backtrace
e               geben-eval-expression
g               geben-run
i               geben-step-into
o               geben-step-over
q               geben-stop
r               geben-step-out
t               geben-show-backtrace
u               geben-unset-breakpoint-line
v               geben-display-context
w               geben-where

C-x SPC         geben-set-breakpoint-line

C-c C-c         geben-run
C-c C-d         geben-unset-breakpoint-line
C-c C-l         geben-where
C-c C-n         geben-step-over
C-c C-s         geben-step-into
C-c C-t         geben-set-breakpoint-line
C-c b           geben-show-breakpoint-list
C-c f           geben-find-file
C-c p           geben-toggle-pause-at-entry-line-flag

Hope this helps.

Read and Post Comments

Google Wave is Dead, Long Live Google Wave

August 05, 2010 at 10:07 AM

They say Google Wave is dead.

I'm having a hard time believing that!

How would a company bring the best and latest technologies to the public, as an open source, open protocol, federated system and pull the plug, a couple of weeks after opening it to the public (without invitation) claiming that they didn't see the adoption they thought they'd have ? It's like developing `postfix` for 4 years, then stopping development just before you ship it to the main distributions so that a real network can live. Of course, if we had only one MTA server on earth, that would be a little problematic for the adoption of e-mail, but Google didn't get (had not yet got) to that point where they allowed for the network to emerge.

Also, large parts of the code is already released, and the specs are out, Novell created their Pulse service and a whole lot followed. How would it be possible that they went to a point where they had a usable product, that any company could potentially take over, and they, the creators of the technology, would just run away in the field. It's like if they were going to miss their own boat!

People say it was difficult to grasp. Come on, you only had to see Wave in use for 5 minutes to start drooling (and understanding). Seriously, it's only a white page, and you can type text in it, make it bold and drag'n'drop some users from a contact list. Is that what people don't grasp ? Sounds to me like some known concepts!

They've invested several millions, they didn't do a lot of fanfare about the product, except that 1h-long video (plus some others, and user contributed videos), so was that only a technology preview for some other things ? Didn't they really believe it could kill e-mail ?

I just can't believe Wave is completely dead, so this is why I list here some of my speculations:

  1. Google is preparing something huge, they've learnt a whole lot about real-time communications, and they'll plug everything into Google Me, which will revolutionize the face of the web, finally making it real-time without the constraints of the Google Wave client (the fact that the wave is inside a single site's iframe).
  2. Google has ported all it's technology to Google Docs (allowing for real-time sharing and collaboration). They have larger adoption there, no need for a separate client, and they'll plug all their robots/gadgets things in there. No need for a new account to a new service to have all the benefits, only feature upgrade. But there again, there is only one central Google Docs, no federation, so that would be against the open-source philosophy, and would mark a regrettable move by Google.
  3. Google will do another incredible move, which I can't even speculate about, that leverages all the awesome technology they've developed in Google Wave, all to users's amazement and satisfaction, and will finally kill e-mail.
  4. They've stepped on a patent from another company and they don't want to go forward because a trial could be fatal for the whole company (perhaps?!?).

UPDATE (16h15): Look below for Eric Schmidt talking about Google Wave's "death"... I think he alludes to my option number 1:

Read and Post Comments

HTML5's EventSource in Pylons (read Comet or AJAX polling)

June 16, 2010 at 05:40 PM

Have you heard of EventSource ? It's very cool.

Here is some Pylons code to implement some sweet HTML5 server-pushing-events to web clients.

The example is based off this post by Rick Waldron. It uses the HTML5 features in Chromium version 6. Follow on his post for install instructions.

So in a random controller, dump this code:

import time
class EventsourceController(BaseController):

    def page(self):
        """Serve a fully fledged HTML page"""
        return '<script src="%s"></script>Loaded...' % url.current(action='js')

    def js(self):
        """Serve the JavaScript referenced by the previous action"""
        response.content_type = 'text/javascript'
        return """
document.addEventListener('DOMContentLoaded', function () {
  
  var eventSrc  = new EventSource('%s');
  
  eventSrc.addEventListener('open', function (event) {
    console.log("OPEN");
    console.log(event.type);
  });
  
  eventSrc.addEventListener('message', function (event) {
    console.log("RECEIVED");
    console.log(event.type);
    console.log(event.data);
  
  });
  console.log("Loaded...");

}, false);
""" % url.current(action='event_sender')

    def event_sender(self):
        """Implement a full-blown Event collector and dispatcher"""
        response.headers['content-type'] = 'text/event-stream'
        # Don't use this! It will append a charset=utf-8 and it won't work.
        #response.content_type = 'text/event-stream'
        response.status_int = 200
        def go():
            for x in range(10):
                msg = "data: %s %s\n\n" % (x, time.time())
                time.sleep(2)
                yield msg
        return go()

With a generator, you can have any code wait for some external events (other users' input, UPS failures, mouse movements on the server) and send some events to your web client.

Make sure you take the ErrorHandler middleware out in config/middleware.py, because it buffers the output: it will keep the data from being flushed to the web user until all the content is finished processing. Another option would be to turn debugging off in your .ini file.

def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
    ...
    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)

    if asbool(full_stack):
        # Handle Python exceptions
        #app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
    ...

Point your browser to your http://.../{controller}/page with Chromium 6, and watch the events being printed to the control (Ctrl+Shift+J).

Now put some Gevent and Greenlet goodness in there, and you'll have some real-time app server in no time!

Read and Post Comments

« Previous Page -- Next Page »