Hey,
so, you want to support Right-To-Left (aka RTL) languages in your
Gaia application, but you don't really know how to do this. Here is
a summary of what I learnt while fixing bug 1053708 [1] for the SMS
app.
1. How to test RTL on the device
Easy:
* Enable "Developer menu" in Settings > Device Information >
More Information
* Enable "Pseudo-localization" in Settings > Developer
* Configure "Mirrored english" in Settings > Language
2. How to test RTL in Firefox
If your application works in Firefox, it's easy with these steps:
* load the application in Firefox
* open Dev Tools
* execute this code:
navigator.mozL10n.language.code = 'qps-plocm'
* if you want to move back to english:
navigator.mozL10n.language.code = 'en-US'
3. Basic RTL introduction
As far as I understand, RTL rules are part of the Unicode
specification. RTL is quite easy if a whole document is in LTR or
RTL. Things get complicated when some part of a document is RTL
while the document is LTR (it's called bi-directionality, aka bidi).
In Unicode, all non punctuation characters embed their writing
directions, they're called "strong". In contrary, all punctuation
characters are "weak".
Unicode also has special characters (called "pseudo strong") that
have no direct output but change RTL behavior. As we'll see, we have
both HTML attributes and CSS properties to change the behavior as
well, and W3C advises to use them instead of the Unicode control
characters [3].
Wikipedia has a nice article:
http://en.wikipedia.org/wiki/Bi-directional_text
4. Basic rules
So, the good news is that all Unicode rules work fine since HTML4
[2].
5. CSS usual properties, what does work?
CSS has a lot of "left" and "right" and "X" and "Y". So what about
them?
Looks like CSS has some RTL-aware properties and values.
text-align: supports start/end
* "start" is "left" in LTR, and "end" in RTL.
* "end" is the opposite
padding: instead of "padding-left" and "padding-right", we can use
"-moz-padding-start" and "-moz-padding-end"
margin: instead of "margin-left" and "margin-right", we can use
"-moz-margin-start" and "-moz-margin-end"
border: same
Shorthands don't work. But if you use shorthand with up to 3 values,
then you don't need to use RTL-aware properties, because left and
right get the same value.
dbaron said the start/end properties do not work exactly like
specified in some situations, but they worked good enough for me.
Properties left/right with absolutely positioned elements have an
interesting property: if there is a conflict between specified
left/right/width and the available width, then the algorithm will
ignore "right" in a LTR context, and will ignore "left" in a RTL
context. You can see an example at [4].
display: inline or inline-block or flex; works out of the box as
you'd expect
5. CSS usual properties, what does not work?
float: does not support start/end, but there has been discussion on
the www-style mailing list.
transform: does not support RTL. No discussion yet.
background-position
top/left when you can't use the "conflict rule". There is some
discussion to support "offset-start" and "offset-end" instead, and a
bug in Gecko (bug 1071099 [7]). After dbaron, there is a "little"
bit of work to do it properly :)
The only way to workaround this is to override the LTR CSS using the
same selectors preceded by [dir=rtl] with the maintenance burden
this gives. It could be a good moment to switch your "float"-based
layout to flexible layout :)
6. HTML and CSS, changing how the BiDi algorithm works
Sometimes, the BiDi algorithm will produce an incorrect result for
some of your cases. It's possible to change how the BiDi algorithm
works. I'll explain here only what we have in HTML and CSS, but not
what we have in pure Unicode.
But first I'll need to explain "embed", "override" and "isolate". I
hope people that know this well won't say I'm simplifying too much
;)
* embed: let you set the direction of some text. We still use the
BiDi algorithm, so if this text contains itself some text that goes
to the opposite direction, then this should do what you expect.
Also, this affects the text _around_ this text, which may do
something you don't expect, especially with punctuation (see [5]).
* override: quite the same, except you don't use the BiDi algorithm
anymore. So if this text contains itself some text that should go to
the opposite direction, it does not.
* isolate: like embedding, except it does not affect the text around
(see [5]).
* isolate-override: like override, but does not affect the text
around.
There is also "plaintext" but I admit I don't get it yet.
These values are actually values for the CSS unicode-bidi property.
isolate, isolate-override and plaintext are prefixed; and to get
"override" you use "bidi-override" in CSS. And then, once you set
once of these values, you can set the "direction" property.
As you see in [5], W3C thinks that "isolate" should now be used by
default, and I think this is what is implemented in Gecko for some
time.
HTML has <bdo> and <bdi> and the "dir" attribute.
Basically:
* setting the "dir" attribute is like setting the CSS property
"unicode-bidi: embed" with a "direction" property, but has more
semantics (works without CSS loaded).
* <bdo dir=""> lets you overriding the BiDi algorithm, so it's
like the CSS value "bidi-override", with more semantics.
* <bdi dir=""> lets you create a "isolate" part, so it's like
the CSS value "isolate" with more semantics. It accepts the magic
attribute "dir='auto'": means that the direction will be calculated
using the first "strong" character. I don't know if we can have the
same behavior with CSS only, probably yes.
You'll find interesting information in the CSS spec [6], and also
some history about isolation in [5].
[1]
https://bugzilla.mozilla.org/show_bug.cgi?id=1053708
[2]
http://www.w3.org/TR/html401/struct/dirlang.html
[3]
http://www.w3.org/International/questions/qa-bidi-controls
[4]
https://github.com/mozilla-b2g/gaia/pull/24301/files#diff-5c046a821160971efb3637477688f024R206
[5]
http://www.w3.org/International/wiki/Html-bidi-isolation#Background
[6]
http://dev.w3.org/csswg/css-writing-modes/#text-direction
[7]
https://bugzilla.mozilla.org/show_bug.cgi?id=1071099
Hope it's been interesting enough :) Don't hesitate to correct, ask
questions, or explain what "plaintext" does :)
Happy RTL-ing !
--
Julien