9
votes

Background

I want to enable right-to-left locales as well as left-to-right, but I only want to maintain a single set of stylesheets.

The idea is that calling application-rtl.css will serve a rtl-converted version of application.css (using r2).

This functionality has two use-cases:

  • development: serve dynamically, converting on the fly
  • production: have precompilation generate the -rtl versions (extending rake assets:precompile task)

So far, I've managed to implement a RTLConverter that enables me to serve all my stylesheets converted to RTL without having touched them at all:

config/initializers/rtl_converter.rb:

require "r2"
require "tilt"

class RTLConverter < Tilt::Template
  def prepare; end

  def evaluate(context, locals, &block)
    R2.r2 @data
  end
end

Rails.application.assets.register_preprocessor 'text/css', RTLConverter

You can also implement this as an engine for sprockets to only convert files having the .rtl extension:

Rails.application.assets.register_engine 'rtl', RTLConverter

My question

How can I hook into the asset pipeline in order to:

  1. serving an on-the-fly converted version of any stylesheet with the name-postfix '-rtl' (look for the file without the postfix and serve a converted version of that)?
  2. creating converted copies with the name-postfix '-rtl' of all stylesheets during precompilation

Notes:

The converter does not work in conjunction with the sass engine, but seems to work fine with less. It's been applied to a twitter-bootstrap based site and works like a charm.

The converter has not been tested in production.

If I can find a decent solution to this problem, I intend to create and maintain a gem and give it back to the community.

4

4 Answers

5
votes

I would aim for just using CSS directly to handle the LTR-RTL differences. CSS can probably handle the job for you. In case you define your CSS as LTR, then, based on a CSS class you can override the stuff you want.

  1. Per default, define your entire CSS stylesheet as LTR.
  2. Put an extra css class on the body which handle the locale. For instance <body class="RTL">
  3. Define all exceptions to the default by overriding with CSS classes prefixed by "RTL"

A short example. Original "default" styles:

body { direction: ltr; }
.sidebar { width: 200px; float: right; margin-left: 30px }

Then, overwrite relevant styles later in your css:

body.rtl { direction: rtl; }
.rtl .sidebar { float: right; margin-right: 30px; }

/*remember to 'reset' all defaults for example: */
.rtl .sidebar { margin-left: 0; }

With sass, you have a common place to define standard variables, for instance margin in the example above. Your mileage may vary. But to me, that sounds more simple than messing with asset pipeline.

4
votes

Unfortunately, none of the other answers really suggested the solution I was looking for, so after digging into matters, I was able to come up with a simple gem that could flip the stylesheet based on the filename.

So by including that gem and serving up a version of the stylesheet with '-flipped' appended to the name, I am now able to serve an automatically flipped version both in dev and production.

Find the gem on rubygems.org: stylesheet_flipper

Find a usage description on gihub: monibuds/stylesheet_flipper

0
votes

As far as I can tell, Sprockets does not expose any hooks into the path lookup mechanism to processors. Even if it did, I don't think you could invoke some generalized "read asset" method.

All in all, I fear that making AP do what you want would require some serious arm-twisting.

So here's a completely different idea. What if you:

  • Dropped on-the-fly asset processing altogether, even in development
  • Had a Guard task set up to
    • recompile assets when their sources change (I think this exists already)
    • generate the RTL versions of the compiled CSS
  • Push the compiled assets to production (gasp!)

In other words, maybe you could trade some of the AP features for increased flexibility?

(I'm not going for the bounty here because this is just an idea, not a solution)

0
votes

Wrote about this issue a year ago:
http://amitkazmirsky.com/2011/05/29/dry-your-rtl-and-ltr-css-files-in-rails-with-sass/

Basically my approach was to write the css with direction as variables:

#user-box {
    backgroud-color: white;
    padding: 0 5px;
    float: $dir;
}

#side-nav {
    margin-#{$opdir}: 5px;
}