Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Noko Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Ruby on Rails i18n revisited

October 3rd, 2005

Having a requirement for both internationalization and per-instance customizability of translations in our soon to be revealed application, I wanted to go with an as-simple-as-possible pure Ruby solution for translating strings.

While gettext based approaches might have some advantages over this (some tools available, possibly faster speed with C-based variants) I didn’t want to go with a sledgehammerized solution (I’ve very few strings in the app, and I really only need to support a handful of languages), so I’ve come up with this:


# .rb files to define l10ns in (lang/ and lang/custom/)
Localization.define('de_DE') do |l|
  l.store "blah", "blub"
  l.store "testing %d", ["Singular: %d", "Plural: %d"]
end

# Call from anywhere (extension to Object class):
_('blah')
_('testing %d', 5)

# in .rhtml
<%=_ 'testing %d', 1 %>

# current language is a class var in class
# Localization, so set e.g. in application.rb
Localization.lang = 'de_DE'

# in environment.rb (rails 0.13.1)
Localization.load

All you need to include for this is the following localization.rb file, which you stick in your lib directory:


module Localization
  mattr_accessor :lang

  @@l10s = { :default => {} }
  @@lang = :default

  def self._(string_to_localize, *args)
    translated =
      @@l10s[@@lang][string_to_localize] || string_to_localize
    return translated.call(*args).to_s if translated.is_a? Proc
    translated =
      translated[args[0]>1 ? 1 : 0] if translated.is_a?(Array)
    sprintf translated, *args
  end

  def self.define(lang = :default)
    @@l10s[lang] ||= {}
    yield @@l10s[lang]
  end

  def self.load
    Dir.glob("#{RAILS_ROOT}/lang/*.rb"){ |t| require t }
    Dir.glob("#{RAILS_ROOT}/lang/custom/*.rb"){ |t| require t }
  end

end

class Object
  def _(*args); Localization._(*args); end
end

It should be easy to alter or extend that for your own purposes, or just use it as-is.

Update: Changed to module; and here’s a very quick hack to extract a nice pre-generated guesstimation of a l10n file:


# Generates a best-estimate l10n file from all views by
# collecting calls to _() -- note: use the generated file only
# as a start (this method is only guesstimating)
def self.generate_l10n_file
  "Localization.define('en_US') do |l|n" <<
  Dir.glob("#{RAILS_ROOT}/app/views/**/*.rhtml").collect do |f|
    ["# #{f}"] << File.read(f).scan(/<%.*[^w]_s*["'](.*?)["']/)
  end.uniq.flatten.collect do |g|
    g.starts_with?('#') ? "n  #{g}" : "  l.store '#{g}', '#{g}'"
  end.uniq.join("n") << "nend"
end

To use that, call up script/console and do a puts Localization.generate_l10n_file.

Update 2: I’ve added support for using nice lambda blocks of code for those “speciality” translations. The block gets passed the *args given to the _ method, so you can basically do anything:


Localization.define do |l|
   l.store '(time)', lambda { |t| t.strftime('%I:%M%p') }
end

Localization.define('de_DE') do |l|
   l.store '(time)', lambda { |t| t.strftime('%H:%M') }
end

_ '(time)', Time.now =>"10:13PM"
Localization.lang = 'de_DE'
_ '(time)', Time.now => "22:13"

An unveiling

October 2nd, 2005

Our company is moving to brand-new offices in the heart of Vienna really soon, so you might want to take a peek.

wollzelle

This will not be the last of our unveilings, so stay tuned. 🙂

P.S. And yes, among other things, we’re working on the next big thing in web apps (written in Ruby on Rails, of course!). 😉

FUD revisited (1): Can you upload files with AJAX?

September 30th, 2005

The short answer is: No.

The long answer is: You can’t, because AJAX get/post data is gathered via JavaScript, and JavaScript has no way at getting at local file contents (for security reasons).

But you can use AJAX to get information on the running upload, as long as your framework has functions that give information on current uploads; and your webserver doesn’t buffer upload data.

In Ruby on Rails that works like this: If you enable the UploadProgress module, Rails stores information about the progress in the session, so while the upload is doing its thing, you can poll the server via an AJAX call and get nice status information. The Upload itself is made via a “traditional” HTML upload form to a hidden IFRAME (the helpers will do all this hard work for you transparently!).

See Sean Treadway’s demo and articles about this.

mir.aculo.us version 3.0

September 27th, 2005

So, as you may have notice because of missing comments and missing trackbacks (well, it’s missing spam too!) I’ve moved mir.aculo.us to be hosted on a shiny Xserve with ultra-fast internet connection.

I’ll fix the remaining glitches over the next few days, but it should work fine basically.

Important: The comments won’t make it back. As I’ve switched from a ages-old beta of Typo to the newest version and also migrated from MySQL to PostgreSQL that’s just too much work…

Prototype leaps forward

September 25th, 2005

Prototype 1.4.0_pre6 is available, and features JSON support, a nice new Range object and some other goodies.

Code says more than words, so have a look at this example.

The final release of script.aculo.us V1.5 will sure put at least some of these additions to good use. 🙂

script.aculo.us V1.5, first release candidate

September 25th, 2005

It’s done! The first release candidate of the upcoming version 1.5 of script.aculo.us is out.

Get it while it’s hot! 🙂

Compared to the previous V1.0, it has tons of new stuff for your web apps to look and feel better:

  • In-place Editor control
  • Slider control
  • Completely new effects engine with queuing, delaying (read: timelines) and text effects
  • DOM Builder
  • Drag and drop and sortables with ghosting
  • Sortables can drag and drop between empty lists
  • Unit testing framework
  • script.aculo.us autoloader (script.aculo.us components get loaded automatically, only one JavaScript file has to be included)

There are also tons of bug fixes and little tweaks to make it all the more enjoyable.

A big thank you to all contributors and bug reporters!

IE6 and the open/save download dialog

September 25th, 2005

t’s great thing for web sites and applications to be able to send files to the user and have the browser download them, instead of just displaying them (at least, this is very, very useful in the application we are developing at the moment).

This can be easily done with sending a:


Content-Type: what/not
Content-Disposition: attachment; filename=“blah.ext”

Ruby on Rails nicely wraps this with the send_file and send_data methods.

But… Internet Explorer 6 displays a dialog to the user, asking if it should open or save the file that it just downloaded. If you choose “open”, Internet Explorer was failing me with not finding the file it just downloaded and the helper application that is calling showing nice error dialogs about that.

So, I started an investigation, and found that Internet Explorer opens the helper applications with the file from it’s cache. If you send along a Cache-Control: no-cache header, Internet Explorer deletes the file from it’s cache before the helper application can open it! Needless to say, Firefox and Safari work fine, because they don’t download files to their cache, but to the download location you set.

A quick and easy workaround is just sending a Cache-Control: private header instead, so that the file stays in the cache.

With my newly acquired powers, I’ve submitted a change to Ruby on Rails, so this shouldn’t be an issue anymore.

Pure Ruby Sparklines

September 17th, 2005

Update October 5, 2009: This is some REALLY old code, but I managed to salvage it recently and put it on Github at http://github.com/madrobby/spark_pr. Please download the code from there!

In Weed, we use Sparklines for displaying web site stats. But, you have to go through the rather tedious process (depending on your setup) of installing RMagick to generate them.

To get rid of the RMagick dependency, I came up with a pure ruby solution, based on why’s excellent Bumpspark and on Geoffrey’s hip gem. The solution currently supports the “smooth” type Sparklines, but i’ll eventually hope to add all types that Geoffrey’s gem supports.

So, you can now have nice “smooth-style” sparklines, just one ruby file required:

Pure Ruby sparkline example

Drawing is done with alpha-blending and antialiased lines.

Grab the source at the Weed collaboa (and consider it beta quality only!).

Update: It now supports ASCII output too, for the GUI challenged:


                                                +++++
                                                +++++
                                                ++#++         +                       +--
                                                ++#++        ---                     -- --+
                                                +++#+        - -                     +
                                      +          + -        +   +     +-             -
                                    -- -         +  -      -     -  -- -+-          -
                              +--  --   -       --  -      -     - --    -+         -
                            --  --+     -       -    -    +       +        --      -
  +++++       +            --            -      +    +  --                  --     +
       --   -- +         -+               +     -    ----                     +-- --
        -- --   +      -+-                 -   --     +                         --+
          +      +  --+-                   -   +
                  +--                       +  +

                                              -

Hello Atlas auto-complexion

September 15th, 2005

Microsoft launched their Atlas AJAX framework, and, you know what, the two top items on their “Behaviours and client components” (warning, Word format) list are “auto-completion” and “drag and drop”. Sound familiar?

First off, looking at their code, they were certainly a bit inspired by my code (and also by Sam’s code). I can see it’s difficult to give credit, but hey, you know, that sucks.

To use Atlas auto-completion, you need to wade through a 23-page long document (warning again, Word format), while you can use the script.aculo.us control with two lines of code in Ruby on Rails.

The codebase is about the same size as the script.aculo.us control, but doesn’t do a lot of things (please correct me if I’m wrong):

  • No CSS-based styling
  • Using cursor keys you can’t use cursor down at the end of a list to go back to the top (same with cursor up at the start of the list)
  • No fade-in/fade-out effects (no wonder, as their “Adding further UI Enahncements” (sic!) section just lists “1. coming soon, 2. coming soon”)
  • No tokenizing (more than one entry being auto-completed)
  • No local completion (using a prepared JavaScript array)

P.S. Did I say that script.aculo.us auto completion fixes the dreaded Internet Explorer “windowed controls” bug, while theirs doesn’t?

Update: Read more on this over at David’s blog.

Double your stats, smoke some weed!

September 13th, 2005

atmos writes:

One of the cool things about being involved in open source stuff is you get to watch things come together and work with people who’re interested in developing something cool with no other driving force but pure interest and the desire to see the end product.

court3nay et al have been hacking on a mint replacement for rails apps. It’s quite cool for about 72 hours of work. It’s still got a long way to go, but keep an eye out for weed as there’s a pretty talented group of folks hacking like madmen on it right now.

So, do keep an eye for weed, as an example for a nice ajaxy Rails app, with source code available. Keep going guys!

Please note that the link is to a demo site, which can be down without notice, as it’s still in development.

Update: More on this on court3nay’s blog!