Salah satu ciri bahasa Arab adalah teks di dalamnya ditulis dan dibaca dari kanan ke kiri. UI untuk bahasa Arab harus dicerminkan secara horizontal (tetapi tidak semuanya dan tidak selalu - ada kehalusan), buka menu konteks di sebelah kiri kursor, dll.
Di bawah potongan - tentang bagaimana kami mendukung RTL (kanan-ke-kiri) di klien web dari 1C: platform Perusahaan, dan juga salah satu hipotesis yang menjelaskan mengapa dunia Arab menulis dari kanan ke kiri.
Sedikit sejarah
Kami terbiasa menulis dari kiri ke kanan. Arah penulisan ini sebagian besar dihasilkan oleh fakta bahwa saat menulis teks di atas kertas, orang yang bertangan kanan (dan menurut statistik, sekitar 85% dari mereka) melihat apa yang telah ditulis - tulisan tangan (kanan) tidak menutupi teks tertulis. Orang kidal harus menderita.
Salah satu hipotesis "mengapa bahasa Arab ditulis dari kanan ke kiri" terdengar seperti ini. Bahasa asal Arab pada masa itu ketika tidak ada kertas dan analoginya (papirus, perkamen, dll.). Hanya ada satu cara untuk mencatat informasi - mengukir huruf di batu. Dan bagaimana akan lebih nyaman bagi orang yang bertangan kanan untuk menggunakan palu dan pahat? Tentu saja, memegang pahat di tangan kirinya dan mengetuknya dengan palu yang dijepit di tangan kanannya. Dan dalam hal ini lebih nyaman menulis dari kanan ke kiri.
Nah, sekarang - tentang bagaimana kita menangani warisan berabad-abad ini.
Bagaimana kami memulai tugas?
Tidak ada pengembang platform yang berbicara bahasa Arab dan tidak memiliki pengalaman dalam mengembangkan antarmuka RTL. Kami telah menyekop banyak artikel tentang topik RTL (saya terutama ingin berterima kasih kepada perusahaan 2GIS atas pekerjaan yang telah dilakukan dan artikel yang dikerjakan dengan cermat: artikel 1 , artikel 2 ). Saat saya mempelajari materi, saya menyadari bahwa kami tidak dapat melakukannya tanpa penutur asli. Oleh karena itu, bersamaan dengan pencarian penerjemah bahasa Arab, kami mulai mencari seorang karyawan - penutur asli bahasa Arab, yang mungkin memiliki pengalaman yang kami butuhkan, dapat memberi tahu kami tentang spesifikasi antarmuka bahasa Arab. Setelah meninjau beberapa kandidat, kami menemukan orang seperti itu dan mulai bekerja.
Mari bermain dengan font
Secara default, kami menggunakan font platform Arial, 10pt. Pengembang konfigurasi tertentu dapat mengubah font untuk sebagian besar elemen antarmuka, tetapi, seperti yang diperlihatkan oleh praktik, hal ini jarang dilakukan. Itu. dalam banyak kasus, pengguna program 1C melihat tulisan yang ditulis oleh Arial di layar mereka.
Arial menampilkan 21 bahasa dengan baik (termasuk Cina dan Vietnam). Namun, ternyata berkat kolega bahasa Arab kami, teks Arab yang disajikan dengan font ini sangat kecil dan sulit dibaca:
100%:
Pengguna Arab cenderung bekerja dalam DPI yang meningkat - 125%, 150%. Situasi membaik pada DPI ini, namun Arial masih sulit dibaca karena sifat fontnya.
125%:
150%:
Kami melihat beberapa opsi untuk menyelesaikan masalah ini:
- Arial , , ( ).
- Arial 11pt RTL-.
- Arial , LTR- Arial.
Saat memilih solusi, kami harus memperhitungkan bahwa font Arial 10pt telah digunakan di 1C: platform Perusahaan untuk waktu yang sangat lama, kami dan mitra kami telah membuat lebih dari 1300 edisi solusi di platform, dan di semuanya font Arial 10pt menunjukkan dirinya dengan baik di semua OS yang didukung (Windows, Linux dan macOS dari berbagai versi), serta di browser. Mengubah font dan / atau ukurannya berarti pengujian besar-besaran terhadap antarmuka pengguna, dan sebagian besar pengujian ini tidak dapat diotomatiskan. Mengubah font juga berarti mengubah antarmuka program yang sudah dikenal untuk pengguna saat ini.
Selain itu, kami tidak dapat menemukan font universal yang dapat mewakili semua bahasa dengan baik, termasuk bahasa Arab. Misalnya, font Segoe UI menampilkan bahasa Arab dengan baik bahkan pada 10pt, tetapi tidak mendukung bahasa China, dan juga tidak didukung di beberapa sistem operasi. Tahoma pandai merender teks bahasa Arab pada 10pt, tetapi memiliki masalah dengan dukungan di Linux dan bahasa Latin / Sirilik yang "terlalu tebal" dalam hal huruf tebal (huruf tebal bahasa Arab terlihat bagus). Dll
Meningkatkan ukuran font default menjadi 11pt di antarmuka RTL berarti pengujian UI yang serius - kami harus memastikan bahwa semuanya dirender dengan benar, semua label ditempatkan di tempat yang disediakan untuk mereka, dll. Dan bahkan pada 11pt, Arial tidak menampilkan aksara arab dengan sempurna.
Hasilnya, cara ketiga ternyata optimal dalam hal biaya tenaga kerja dan efek yang dicapai: kami terus menggunakan Arial untuk semua karakter kecuali bahasa Arab. Dan untuk karakter Arab, kami menggunakan font yang cocok untuk ini - Almarai . Untuk melakukan ini, tambahkan ke CSS:
@font-face {
font-family: 'Almarai';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Almarai'),
local('Almarai-Regular'),
url(https://fonts.gstatic.com/s/almarai/v2/tsstApxBaigK_hnnQ1iFo0C3.woff2)
format('woff2');
unicode-range:
U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
lalu di mana pun Anda perlu menggunakan fonta default, atur font dengan cara ini:
font-family: 'Almarai', Arial, sans-serif;
Keunggulan dari pendekatan ini adalah jika tidak ada satu karakter pun di antarmuka yang termasuk dalam rentang unicode, maka font itu bahkan tidak akan dimuat. Tetapi begitu simbol seperti itu muncul, browser akan mengunduh font itu sendiri (atau menggunakan versi lokalnya) dan menampilkan simbol tersebut dalam font yang diinginkan.
Antarmuka "Balik"
Seperti yang Anda duga, tata letak HTML klien web belum siap untuk dibalik. Setelah mengambil langkah pertama, menyetel atribut dir = ”rtl” pada elemen root dan menambahkan gaya html [dir = rtl] {text-align: right;} , kami memulai pekerjaan yang melelahkan. Selama pekerjaan ini, kami telah mengembangkan sejumlah praktik yang ingin kami bagikan di sini.
Simetri
Mari kita lihat contoh tombol. Tombol di platform dapat berisi gambar, teks dan penanda daftar drop-down. Dan semua ini dalam komposisi apa pun atas kebijaksanaan pengembang solusi aplikasi berdasarkan platform.
Kolom "sebelum RTL" secara grafis mewakili padding awal elemen tombol. Ketergantungan jumlah indentasi pada keberadaan elemen di tombol, serta urutan pengaturannya, sudah jelas. Jika ada gambar, maka teks tidak memerlukan indentasi kiri, jika gambar ada di kanan, maka gambar bergeser negatif, jika ada marker di drop-down list, container dengan teks lebih banyak indent di sebelah kanan, jika marker berada tepat setelah gambar, ia juga memiliki margin di sebelah kanan. Terlalu banyak jika, kecuali tombol hanya teks dengan padding simetris. Simetris! Jika Anda mendistribusikan indentasi secara simetris, maka tidak ada yang bisa dibalik. Ini menjadi ide utamanya.
Kolom "setelah RTL" menunjukkan indentasi simetris baru pada tombol yang sama. Tetap menyelesaikan nuansa dengan lekukan antara gambar dan penanda daftar. Saya menginginkan solusi universal untuk orientasi apa pun. Segitiga itu sendiri digambar dengan batas atas pada pseudo-element, dan itu membutuhkan indentasi hanya jika itu setelah gambar. Dalam kondisi ini, elemen semu lain ditambahkan dengan lebar indentasi yang diperlukan. Segitiga dan bantalan dengan sendirinya akan bertukar ketika orientasi diubah.
Catatan. Semua contoh di bawah ini secara default untuk antarmuka LTR. Untuk melihat seperti apa contoh di antarmuka RTL, ubah dir = "ltr" menjadi dir = "rtl".
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.button {
display: inline-flex;
align-items: center;
border: 1px solid #A0A0A0;
border-radius: 3px;
height: 26px;
padding: 0 8px;
}
.buttonImg {
background: #A0A0A0;
width: 16px;
height: 16px;
}
.buttonBox {
margin: 0 8px;
}
.buttonDrop {
display: flex;
}
.buttonDrop:after {
content: '';
display: block;
border-width: 3px 3px 0;
border-style: solid;
border-left-color: transparent;
border-right-color: transparent;
}
.buttonImg + .buttonDrop::before {
content: '';
display: block;
width: 8px;
overflow: hidden;
}
</style>
</head>
<body>
<a class="button">
<span class="buttonImg"></span>
<span class="buttonBox"></span>
<span class="buttonDrop"></span>
</a>
<a class="button">
<span class="buttonImg"></span>
<span class="buttonDrop"></span>
</a>
</body>
</html>
Kami mencoba untuk menghindari elemen, pseudo-elemen, dan pembungkus yang tidak perlu. Namun, dalam hal ini membuat pilihan antara meningkatkan kondisi dalam CSS dan menambahkan elemen pseudo, solusi dengan elemen semu menang karena keserbagunaannya. Tidak banyak tombol seperti itu di formulir, sehingga kinerja saat menambahkan elemen tidak akan terganggu bahkan di Internet Explorer.
Prinsip simetri juga terbukti berguna dalam menggulir panel kita. Untuk memindahkan konten secara horizontal, kami sebelumnya menerapkan satu properti margin-left: -Npx; ...
Nilai sekarang disetel ke margin simetris : 0 -Npx; , yaitu untuk kiri dan kanan sekaligus, dan ke mana harus bergerak - browser itu sendiri tahu, tergantung pada arah yang ditentukan.
Kelas atom
Salah satu kemampuan platform kami adalah kemampuan untuk mengubah konten secara dinamis dan lokasinya pada bentuk "on the fly" sesuai selera masing-masing pengguna. Kasus umum perubahan adalah perataan horizontal teks: kiri, kanan, atau tengah. Ini dicapai hanya dengan menyelaraskan teks dengan nilai yang sesuai. Pembalikan RTL berarti memperluas kondisi dalam skrip dan gaya untuk setiap kontrol dan untuk setiap kasus pemosisiannya. Solusi minimum membutuhkan 4 baris:
.taStart {
text-align: left;
}
html[dir=rtl] .taStart {
text-align: right;
}
.taEnd {
text-align: right;
}
html[dir=rtl] .taEnd {
text-align: left;
}
Jadi, di tempat yang diperlukan, kelas dipasang dengan pelurusan yang diperlukan dan penggantiannya yang mudah jika perlu. Tetap hanya mengganti pengaturan penyelarasan dengan style = "text-align: ..." dengan kelas yang sesuai.
Prinsip yang sama digunakan untuk mengatur jenis kesejajaran lainnya - float .
.floatStart {
float: left;
}
html[dir=rtl] .floatStart {
float: right;
}
.floatEnd {
float: right;
}
html[dir=rtl] .floatEnd {
float: left;
}
Dan, tanpa itu, kelas untuk pencerminan, misalnya, ikon, yang juga dipasang di wadah apa pun yang perlu pencerminan di antarmuka RTL.
html[dir=rtl] .rtlScale {
transform: scaleX(-1);
}
Antiscale
Setelah berurusan dengan elemen linier "sederhana", sekarang saatnya beralih ke elemen "kompleks". Ada juga beberapa di platform kami, misalnya, sakelar sakelar. Mereka bisa dari berbagai bentuk geometris. Browser mengatasi pengaturan elemen, indentasi di sakelar sakelar kami awalnya simetris. Jadi apa masalahnya? Masalahnya ada pada pembulatan bingkai.
Pembulatan bingkai dihitung untuk setiap elemen sakelar sakelar, bergantung pada posisinya. "Kiri-atas", "kanan-atas", "kanan-atas dan kanan-bawah" - variasinya berbeda.
Anda dapat membalik seluruh wadah dengan sakelar sakelar, tetapi bagaimana dengan teks, yang juga membalik? Kami menyebut teknik ini "anti-skala" . Tambahkan kelas atom rtlScale ke wadah yang perlu dicerminkan, dan tambahkan properti transform inheritance ke elemen anaknya : inherit; ... Di antarmuka LTR, metode ini akan diabaikan, tetapi untuk antarmuka RTL, teks, yang dibalik dua kali, akan ditampilkan sesuai kebutuhan.
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
html[dir=rtl] .rtlScale {
transform: scaleX(-1);
}
.tumbler {
display: inline-flex;
border-radius: 4px 0 0 4px;
border: 1px solid #A0A0A0;
padding: 4px 8px;
}
.tumblerBox {
transform: inherit;
}
</style>
</head>
<body>
<div class="tumbler rtlScale">
<div class="tumblerBox"> </div>
</div>
</body>
</html>
Flexbox
Tentu saja, sayangnya, kami tidak menemukan teknologi luar biasa ini, tetapi dengan senang hati kami menggunakan kemampuannya untuk tujuan kami. Misalnya, di panel bagian. Tombol gulir panel ini tidak memakan tempat; tombol tersebut muncul di atas panel bila memungkinkan untuk menggulir ke satu arah atau lainnya. Implementasi yang cukup logis dari posisi: absolut; kanan / kiri: 0; ternyata tidak universal, jadi kami meninggalkannya. Akibatnya, solusi universal mulai terlihat seperti ini: setel wadah induk dari tombol gulir ke lebar nol sehingga tidak memakan tempat, dan orientasi tombol gulir yang terletak di ujung diubah melalui flex-direction: row-reverse; ...
Dengan demikian, tombol di akhir baris ditekan ke ujung baris wadah lebar-nol dan ditampilkan "mundur" di atas panel.
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.panel {
display: inline-flex;
background: #fbed9e;
height: 64px;
width: 250px;
}
.content {
width: 100%;
}
.scroll {
display: flex;
position: relative;
width: 0;
}
.scrollBack {
order: -1;
}
.scrollNext {
flex-direction: row-reverse;
}
.scroll div {
display: flex;
flex: 0 0 auto;
justify-content: center;
align-items: center;
background: rgba(255,255,255,0.5);
width: 75px;
}
</style>
</head>
<body>
<div class="panel">
<div class="content"> </div>
<div class="scroll scrollBack">
<div></div>
</div>
<div class="scroll scrollNext">
<div></div>
</div>
</div>
</body>
</html>
Ngomong-ngomong, ide lebar-nol ternyata berguna untuk memecahkan masalah lain juga. Elemen drop-down (menu konteks, daftar drop-down, dll.) Banyak digunakan di platform. Perhitungan pemosisian itu rumit dan halus, oleh karena itu pencerminan membutuhkan lebih banyak kerumitan dan kehalusan.
Solusinya adalah meletakkan dropdown dalam wadah berukuran nol (disebut jangkar). Jangkar diposisikan secara mutlak pada titik antarmuka yang diperlukan, dan kontennya dengan tepi awalnya ditekan ke tepi awal jangkar, memposisikan konten ke arah yang diinginkan.
<!DOCTYPE html>
<html dir="ltr">
<head>
<style>
.anchor {
border: 1px solid red;
position: absolute;
width: 100px;
height: 50px;
max-width: 0;
max-height: 0;
top: 25%;
left: 50%;
}
.anchorContent {
background: #FFF;
border: 1px solid #A0A0A0;
width: inherit;
height: inherit;
padding: 4px 8px;
}
</style>
</head>
<body>
<div class="anchor">
<div class="anchorContent"> </div>
</div>
</body>
</html>
Elemen yang benar-benar diposisikan
Jika pemosisian absolut elemen tidak dapat dihindari ( style = "position: absolute;" atau style = "position: fixed;" ), dir = "rtl" tidak berdaya. Suatu pendekatan datang untuk menyelamatkan ketika koordinat horizontal diterapkan bukan pada gaya kiri , tetapi pada gaya kanan .
Selain itu, jika di JS, saat menghitung koordinat, ada daya tarik ke properti scrollLeft dan offsetLeft elemen, maka di antarmuka RTL, menggunakan properti ini secara langsung dapat menyebabkan konsekuensi yang tidak terduga. Anda perlu menghitung nilai properti ini dengan cara yang berbeda. Penerapan fungsi ini di Google Closure Library, yang kami gunakan di klien web, telah membuktikan dirinya dengan baik: lihat.https://github.com/google/closure-library/blob/master/closure/goog/style/bidi.js .
Akhirnya
Kita berhasil! Kami menyerahkan dan menyimpan kode sumber kami dalam satu versi untuk antarmuka LTR dan RTL. Kebutuhan tersebut belum muncul, tetapi jika diinginkan, kita dapat menampilkan dua bentuk arah yang berbeda secara bersamaan pada satu halaman. Dan omong-omong, dengan menggunakan teknik kami, kami berakhir dengan file CSS akhir 25% lebih ringan.
Kami juga mendukung RTL di klien 1C tipis (asli) yang berfungsi di Windows, Linux, dan macOS, tetapi ini adalah topik untuk artikel terpisah.