Skip to content

Commit 7dbe817

Browse files
Improve RTL Rendering for Guides (rails#51613)
Improve RTL language support, specifically focused on Arabic (MSA), Farsi, and Hebrew languages, including custom fonts for those languages, a javascript to detect auto-translation and shift the dir attribute, and other cleanup based on volunteer feedback. Co-authored-by: Carlos Antonio da Silva <[email protected]>
1 parent bc727a0 commit 7dbe817

File tree

4 files changed

+102
-27
lines changed

4 files changed

+102
-27
lines changed

guides/assets/javascripts/guides.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,15 @@
186186
}
187187
})
188188
});
189+
190+
// Observe the HTML tag for Google Translate CSS class, to swap our lang direction LTR/RTL.
191+
var observer = new MutationObserver(function(mutations, _observer) {
192+
each(mutations, function(mutation) {
193+
if (mutation.type === "attributes" && mutation.attributeName == "class") {
194+
mutation.target.dir = mutation.target.classList.contains("translated-rtl") ? "rtl" : "ltr";
195+
}
196+
})
197+
});
198+
observer.observe(document.querySelector("html"), { attributeFilter: ["class"] });
199+
189200
}).call(this);

guides/assets/stylesrc/_main.scss

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ body.guide {
1717

1818
-webkit-tap-highlight-color:rgba(38, 27, 35, 0);
1919

20+
2021
// ----------------------------------------------------------------------------
2122
// Typographic Baseline
2223
// ----------------------------------------------------------------------------
@@ -57,7 +58,6 @@ body.guide {
5758

5859
margin: 0 0 0.75em 0; // Space after paragraph
5960
text-align: left;
60-
6161
} // p
6262

6363
// Links
@@ -259,12 +259,6 @@ body.guide {
259259
}
260260
} // dd
261261
} // dl
262-
263-
// :where(&[dir="ltr"]) dd { margin-left: 1.5em; }
264-
// :where(&[dir="rtl"]) dd { margin-right: 1.5em; }
265-
266-
// :where(&[dir="ltr"]) :is(dd) { margin-left: 0; padding-left: 0; }
267-
// :where(&[dir="rtl"]) :is(dd) { margin-right: 0; padding-right: 0; }
268262

269263
li {
270264
margin-bottom: 0.5em;
@@ -274,7 +268,7 @@ body.guide {
274268

275269
pre, code {
276270
font-size: 1rem;
277-
font-family: "IBM Plex Mono", "Anonymous Pro", "Inconsolata", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace;
271+
font-family: "IBM Plex Mono", "Anonymous Pro", "Inconsolata", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace !important;
278272
line-height: 1.5;
279273
margin: 1em 0;
280274
overflow: auto;
@@ -322,14 +316,17 @@ body.guide {
322316

323317
.wrapper {
324318
padding: 1em;
325-
326-
:where(body[dir="ltr"]) & { text-align: left; }
327-
:where(body[dir="rtl"]) & { text-align: right; }
319+
text-align: left;
328320

329321
@include media('>desktop') { // 1024
330322
max-width: calc(55rem + 420px);
331323
margin: 0 auto;
332324
padding-right: 470px;
325+
326+
:where(html[dir="rtl"]) & {
327+
padding-right: 1.5em;
328+
padding-left: 470px;
329+
}
333330
}
334331
} // .wrapper
335332

@@ -584,8 +581,8 @@ body.guide {
584581
z-index: 15;
585582
padding-bottom: 0.125em;
586583

587-
:where(body[dir="ltr"]) & { background-position: right top; padding-right: 1em; }
588-
:where(body[dir="rtl"]) & { background-position: left top; padding-left: 1em; }
584+
:where(html[dir="ltr"]) & { background-position: right top; padding-right: 1em; }
585+
:where(html[dir="rtl"]) & { background-position: left top; padding-left: 1em; }
589586
}
590587

591588

@@ -604,8 +601,8 @@ body.guide {
604601
max-width: 1000px;
605602
z-index: 10;
606603

607-
:where(body[dir="ltr"]) & { left: auto; right: 50px; }
608-
:where(body[dir="rtl"]) & { left: 50px; right: auto; }
604+
:where(html[dir="ltr"]) & { left: auto; right: 50px; }
605+
:where(html[dir="rtl"]) & { left: 50px; right: auto; }
609606

610607
&.visible {
611608
display: block !important;
@@ -706,6 +703,11 @@ body.guide {
706703
right: 50px;
707704
max-height: calc(100vh - 200px);
708705
width: 400px;
706+
707+
:where(html[dir="rtl"]) & {
708+
right: auto;
709+
left: 50px;
710+
}
709711
}
710712

711713
&.guide-index {
@@ -714,11 +716,20 @@ body.guide {
714716

715717
@include media('>desktop-ultra-wide') {
716718
right: calc(30vw - 400px);
719+
720+
:where(html[dir="rtl"]) & {
721+
right: auto;
722+
left: calc(30vw - 400px);
723+
}
717724
}
718725

719726
@include media('>desktop-hd') { // 1920
720-
721727
right: calc(40vw - 400px);
728+
729+
:where(html[dir="rtl"]) & {
730+
right: auto;
731+
left: calc(40vw - 400px);
732+
}
722733
}
723734

724735
h3.chapter img {
@@ -820,6 +831,11 @@ body.guide {
820831
background-color: $stop-bkgnd;
821832
opacity: 0;
822833
transition: opacity 0.2s ease-in-out;
834+
835+
:where(html[dir="rtl"]) & {
836+
right: -3.5em;
837+
left: unset;
838+
}
823839
}
824840

825841
a.active::after {
@@ -838,6 +854,11 @@ body.guide {
838854
background-color: $rf-brand;
839855
opacity: 0;
840856
transition: opacity 0.2s ease-in-out;
857+
858+
:where(html[dir="rtl"]) & {
859+
right: -3em;
860+
left: unset;
861+
}
841862
}
842863

843864
a.active::before {
@@ -852,4 +873,40 @@ body.guide {
852873
}
853874
}
854875

855-
} // body.guide
876+
} // body.guide
877+
878+
html[dir="rtl"] {
879+
body.guide {
880+
direction: rtl;
881+
882+
p, table th, .wrapper,
883+
#guides .guides-section-container .guides-section {
884+
text-align: right;
885+
}
886+
} // body.guide
887+
888+
&:lang(ar), &:lang(fa) {
889+
body.guide {
890+
h1, h2, h3, h4, h5, h6, p, dl, dd, dt, ul, ol, li,
891+
header#page_header nav#feature_nav .header-logo a {
892+
font-family: "Noto Sans Arabic", sans-serif !important;
893+
font-optical-sizing: auto;
894+
font-weight: 400;
895+
font-style: normal;
896+
font-variation-settings: "wdth" 100;
897+
}
898+
} // body.guide
899+
} // &:lang(ar), &:lang(fa)
900+
901+
&:lang(he), &:lang(iw) {
902+
body.guide {
903+
h1, h2, h3, h4, h5, h6, p, dl, dd, dt, ul, ol, li,
904+
header#page_header nav#feature_nav .header-logo a {
905+
font-family: "Heebo", sans-serif !important;
906+
font-optical-sizing: auto;
907+
font-weight: 400;
908+
font-style: normal;
909+
}
910+
} // body.guide
911+
} // &:lang(he), &:lang(iw)
912+
} // html[dir="rtl"]

guides/assets/stylesrc/components/_code-container.scss

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@
88
/* Same bottom margin for special boxes than for regular paragraphs, this way
99
intermediate whitespace looks uniform. */
1010

11-
.interstitial {
11+
.interstitial,
12+
dl dd .interstitial {
1213
background-repeat: no-repeat;
1314
background-size: 36px 36px;
1415
border-radius: $base-border-radius;
1516
border: 2px solid $gray-500;
1617
border-style: solid !important;
1718
border-width: 2px !important;
18-
min-height: calc(36px + 1.2em);
19+
min-height: calc(36px + 1.5em);
1920
margin: 2em auto;
2021
padding: 0.75em !important;
2122
position: relative;
2223

2324
// Padding and spacing for LTR vs RTL langauge defaults
24-
:where(body[dir="ltr"]) & { background-position: 10px 10px; padding-right: 1em !important; padding-left: 56px !important; }
25-
:where(body[dir="rtl"]) & { background-position: calc(100% - 10px) 10px; padding-right: 56px !important; padding-left: 1em !important; }
25+
:where(html[dir="ltr"]) & { background-position: 10px 10px; padding-right: 1em !important; padding-left: 56px !important; }
26+
:where(html[dir="rtl"]) & { background-position: calc(100% - 10px) 10px; padding-right: 56px !important; padding-left: 1em !important; }
2627

2728
/* Remove bottom margin of paragraphs in special boxes, otherwise they get a
2829
spurious blank area below with the box background. */
@@ -39,6 +40,8 @@ intermediate whitespace looks uniform. */
3940
background-color: $gray-900;
4041
min-height: auto; // remove if icon is restored
4142
padding-left: 1em !important; // remove if icon is restored
43+
direction: ltr !important;
44+
text-align: left !important;
4245

4346
pre {margin: 0;}
4447

@@ -52,9 +55,9 @@ intermediate whitespace looks uniform. */
5255
padding: 0.25em 0.5em !important;
5356
position: absolute;
5457
bottom: 10px;
55-
:where(body[dir="ltr"]) & { right: 10px; }
56-
:where(body[dir="rtl"]) & { left: 10px; }
58+
right: 10px;
5759
text-transform: uppercase;
60+
width: auto;
5861
} // button.clipboard-button
5962
} // &.code
6063

@@ -92,5 +95,4 @@ intermediate whitespace looks uniform. */
9295
&.kindle {
9396
padding-top: 1em !important;
9497
}
95-
} // .interstitial
96-
98+
} // .interstitial

guides/source/layout.html.erb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html dir="<%= @direction %>" lang="en">
33

44
<head>
55
<meta charset="utf-8">
@@ -25,10 +25,15 @@
2525
<meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" />
2626
<meta property="og:type" content="website" />
2727

28+
<link rel="preconnect" href="https://fonts.googleapis.com">
29+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
30+
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
31+
<link href="https://fonts.googleapis.com/css2?family=Heebo:[email protected]&family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
32+
2833
<meta name="theme-color" content="#C81418">
2934
</head>
3035

31-
<body dir="<%= @direction %>" class="guide">
36+
<body class="guide">
3237
<nav id="topNav" aria-label="Secondary">
3338
<div class="wrapper">
3439
<strong class="more-info-label">More at <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong>

0 commit comments

Comments
 (0)