Automatic RTLing


(Noam Yorav-Raphael) #1

The current method of RTL support is the file rtl.scss, which tries to patch the rest of Discourse’s CSS to fix the direction. There were a lot of quirks, and recently @Qasem_h submitted a lot of updates to it.

I think this method is fragile and will always leave RTL support lacking. It basically means that rtl.scss should patch every directionality-dependent CSS in every other file, which is a lot, and will continue to expand.

In my previous attempt at an Israeli political discussion forum, I used CSSJanus to flip the entire reddit CSS. You can see the result here: פורום “לצאת מהקופסה”. From my experience, it worked great. CSSJanus is a stand-alone Python script that flips the direction of a CSS file. (Note: there’s a javascript version here – I haven’t tested it.)

I think that the best way would be to run CSSJanus on desktop.css to create desktop-rtl.css, and for RTL languages use desktop-rtl.css.

(I’m not sure how to even test this – if I modify stylesheet-cache/desktop.css it gets overwritten. It seems that discourse_stylesheets.rb is responsible, and I tried to edit it, but with no effect – is there anything I have to do after I edit a .rb file?)


RTL support
#2

I thing this is not good idea , cuse CSSJanus is just set left to right , you can try it but it wont work well


(Noam Yorav-Raphael) #3

I tried it on reddit, which is fairly complex. It worked great.

Some extra tweaks might be needed, but I don’t think that’s a reason not to use it.


(Sam Saffron) #4

Why not try it and post some screenshots


(Noam Yorav-Raphael) #5

I tried to try it, but didn’t manage to. How can I overwrite desktop.css manually?


#6

im tested it with meta css codes , not work properly



(Noam Yorav-Raphael) #7

After I edit discourse_stylesheets.rb, are there any commands I need to run before the changes take effect? I commented out

    File.open(stylesheet_fullpath, "w") do |f|
      f.puts css
    end

which seems to be responsible for writing desktop.css, with no effect.


(Simon Cossar) #8

That sounds interesting. I have been going through the Discourse stylesheets to try to improve the RTL support. I have essentially been doing what CSSJanus says it does - switching floats, padding, margins. That takes care of most of the problems.

If you want to see where things are at with it - take a look here http://104.236.244.77/
try http://104.236.244.77/?mobile_view=1 to see it with a mobile view.

You will see there are still a few problems. I can switch the language over to Hebrew for you to try if that would be helpful.


(Simon Cossar) #9

There is also a cssjanus node module:

If you don’t go with the cssjanus approach, we can have a maintainable rtl setup for Discourse in the next couple of days. The current state of the code is here https://github.com/scossar/custom-discourse/tree/mobile_rtl

It started out as a series of patches on rtl.scss, but it now seems that it is worth manually going through the discourse scss files and extracting all the rules to do with direction, margins etc. I have approached mobile/rtl.scss in that way.

I’m happy to do it, but maybe it is too much to maintain,


(Sam Saffron) #11

I think the best approach we could use it to add something like cssjanus automatically and then layer all the exceptions on to that in an extra file.

I really dislike having a massive RTL css file that needs to be updated over time. If you feel like working on something like this it would be welcome.


(Simon Cossar) #12

Yes, I am starting to see the problem :dizzy_face:

One possible approach is outlined in this article on managing rtl css with Sass and Grunt.

The basic idea is to define Sass variables for $default-float, $opposite-float, $default-direction, and $opposite-direction in the main scss files. You can then do things like this:

// LTR languages directions.
// ltr-app.scss
 
$default-float:          left;
$opposite-float:        right;
 
$default-direction:       ltr;
$opposite-direction:      rtl;
 
// Import the main style
 
@import 'style';

// ----------------------------------

// RTL languages directions.
// rtl-app.scss
 
$default-float:         right;
$opposite-float:         left;
 
$default-direction:       rtl;
$opposite-direction:      ltr;
 
// Import the main style
 
@import 'style';

// style.scss

 body {
    direction: $default-direction;
}
 
.media {
    float: $default-float;
    padding-#{$opposite-float}: 10px;
} 

Sass mixins could be defined for for float, padding, margin etc.

@mixin margin-left($unit) {
  margin-#{$default-float}: $unit;
}
 
@mixin margin-right($unit) {
  margin-#{$opposite-float}: $unit;
}

and then used like:

 #topic-closing-info {
    @include margin-right(10px);
  }

(Simon Cossar) #13

That is actually quite simple to do. It’s just a matter or replacing float, text-align, margin, margin-right, margin-left, padding, padding-right, padding-left, left, and right with these mixins. Also direction needs to be defined on the body as a variable. LTR or RTL styles can be generated by changing the $direction, $default-float, and $opposite-float variables.

There are a few things that would still have to be tweaked - mostly arrow and icon directions.

The float and padding mixins are set to take a list as an argument, so everything can initially be set up with search-and-replace from a text editor without having to worry about dealing with commas.

$direction: ltr;
$default-float: left;
$opposite-float: right;

//$direction: rtl;
//$default-float: right;
//$opposite-float: left;

// Mixins

// replaces float:
@mixin float($dir) {
  @if $dir == left {
    float: $default-float;
  } @else if $dir == right {
    float: $opposite-float;
  } @else {
    float: $dir;
  }
}

// replaces text-align:
@mixin text-align($dir) {
  @if $dir == left {
    text-align: $default-float;
  } @else if $dir == right {
    text-align: $opposite-float;
  } @else {
    text-align: $dir;
  }
}

// replaces padding-left:
@mixin padding-left($padding) {
  @if $default-float == left {
    padding-left: $padding;
  } @else {
    padding-right: $padding;
  }
}

// replaces padding-right:
@mixin padding-right($padding) {
  @if $default-float == left {
    padding-right: $padding;
  } @else {
    padding-left: $padding;
  }
}

// replaces margin-left:
@mixin margin-left($margin) {
  @if $default-float == left {
    margin-left: $margin;
  } @else {
    margin-right: $margin;
  }
}

// replaces margin-right:
@mixin margin-right($margin) {
  @if $default-float == left {
    margin-right: $margin;
  } @else {
    margin-left: $margin;
  }
}

// replaces margin:
@mixin margin($margins) {
  @if length($margins) < 4 {
    margin:  $margins;
  } @else if length($margins) == 4 {
    @if $default-float == left {
      margin: $margins;
    } @else {
      margin: nth($margins, 1) nth($margins, 4) nth($margins, 3) nth($margins, 2);
    }
  } @else {
    // Deal with the possibility of 4 arguments plus !important
  }
}

// replaces padding:
@mixin padding($padding) {
  @if length($padding) < 4 {
    padding:  $padding;
  } @else if length($padding) == 4 {
    @if $default-float == left {
      padding: $padding;
    } @else {
      padding: nth($padding, 1) nth($padding, 4) nth($padding, 3) nth($padding, 2);
    }
  } @else {
    // Deal with the possibility of 4 arguments plus !important
  }
}

// replaces left:
@mixin left($amount) {
  @if $default-float == left {
    left: $amount;
  } @else {
    right: $amount;
  }
}

// replaces right:
@mixin right($amount) {
  @if $default-float == left {
    right: $amount;
  } @else {
    left: $amount;
  }
}


(Sam Saffron) #14

This looks quite cool, so we would just include this mixin conditionally on ltr, can you do a PR for this?


(Simon Cossar) #15

I was imagining using it to generate separate style sheets - rtl and ltr for desktop and mobile. Then conditionally loading the stylesheets depending on the language.


(Kane York) #16

That makes more sense than including all the rtl rules in the main stylesheet served to English sites, though it does make the pipeline even more complicated :stuck_out_tongue:


#17

We work on this PR,I hope that work properly


(Simon Cossar) #18

I don’t have a very clear understanding of the pipeline. I’m starting to look into it. Any pointers to a good, basic reference would be appreciated.

— Edit —

From RailsGuides - The Asset Pipeline

###1 What is the Asset Pipeline?
The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and pre-processors such as CoffeeScript, Sass and ERB.

Reading the Rail Guide on the Asset pipeline along with the Sprockets Rails README has been quite helpful. I’ll try to write up something about it in a separate topic.


(Simon Cossar) #19

So far everything with this approach is working quite well. What we are still missing is a conditional check for rtl_view and rtl_mobile_view to be used inside of the DiscourseStylesheets.stylesheet_link_tag.


(Simon Cossar) #20

This is working now. You can try it out at http://104.236.244.77/ . The language is set to Persian, but I can change that to Hebrew or Arabic if anyone wants to try it out in those languages.

rtl.scss is now only 21 lines long. Most of that is a rotate mixin to rotate the font awesome right-caret.

Doing the RTLing this way involved adding mixins to the base Discourse stylesheets. It may be that that is a problem.

Either @Qasem_h or I will make a PR for this later today.


(Simon Cossar) #21

I like the Sass mixin solution, but I can see good reasons why it won’t be used - especially when there is something as simple as the first solution proposed in this thread.
Using the node version of cssjanus GitHub - cssjanus/cssjanus: Convert CSS stylesheets between left-to-right and right-to-left., all that is required is something like this:

In the root of the project npm install cssjanus --save-dev

// flipit.js 

var fs = require('fs');
var  cssjanus = require('./node_modules/cssjanus');

fs.readFile('public/uploads/stylesheet-cache/desktop.css', function (err, styles_left) {
  if (err) {
    throw err;
  }
  var styles_right = cssjanus.transform(styles_left.toString());
  fs.writeFile('public/uploads/stylesheet-cache/desktop_rtl.css', styles_right, function (err) {
    if (err) {
      throw err;
    }
  });
});

For my own testing I copied the file to app/assets/stylesheets/ and changed the code in _discourse_stylesheets.html.erb to <%= stylesheet_link_tag "desktop_rtl" %>.

It looks great. There’s probably a way to automate it. The end result should be the same as the mixin soluntion.