من اليمين إلى اليسار. كيفية تحويل واجهة الموقع تحت RTL

الصورة


لقد قمنا مؤخرًا بترجمة النسخة الإلكترونية من 2GIS إلى اللغة العربية ، وفي مقال سابق تحدثت عن النظرية اللازمة لذلك - ما هو dir="rtl" ، وبأي قواعد يتم عرض نص مختلط التركيز وكيفية التحكم في نفسك.


لقد حان الوقت لبدء الممارسة - لتحويل الواجهة بأكملها من اليمين إلى اليسار بأقل جهد حتى لا يشعر العربي الحقيقي بالصيد.


في هذه المقالة ، سأخبرك بكيفية وضع نموذج سريع لما يجب فعله مع تجميع CSS والعكازات التي يجب أن تتحلل في JS ، ولاحظ القليل عن ميزات الترجمة والتعريب ، واستذكر الخصائص المنطقية لـ CSS ولمس موضوع RTL في CSS-in-JS.


أنماط التقليب


عندما قمت بتطبيق السمة dir = "rtl" على العلامة ، تم تغيير الترتيب الضمني للعناصر فقط - على سبيل المثال ، ترتيب خلايا الجدول أو العناصر المرنة. لم يحدث شيء مع القيم المحددة صراحة في الأنماط.

خذ أنماط بعض الإشعارات الموجودة في أسفل اليمين:


 .tooltip { position: 'absolute'; bottom: 10px; right: 10px; } 

لن تؤثر dir="rtl" على هذه الأنماط بأي شكل من الأشكال - في إصدار RTL سيكون تلميح الأدوات أيضًا على اليمين ، على الرغم من أنه متوقع على اليسار.


ماذا تفعل تحتاج إلى استبدال right: 10px left: 10px . وهكذا مع جميع الأنماط الأخرى. الموضع المطلق ، الهامش / الحشو ، محاذاة النص - كل شيء يجب أن يدور في الاتجاه المعاكس للنسخة العربية.


نموذج سريع


بادئ ذي بدء ، يمكنك ، دون تردد ، تغيير جميع حالات اليسار إلى اليمين والقيام ببعض السحر مع قيم الاختزال:


  • يسار: 0 → يمين: 0
  • المساحة المتروكة اليسرى: 4 بكسل ← المساحة المتروكة اليمنى: 4 بكسل
  • الهامش: 0 16 بكسل 0 0 ← الهامش: 0 0 0 16 بكسل

البرنامج المساعد postcss-rtl مناسب لذلك. ملائم - تحتاج فقط لإسقاطه في قائمة جميع المكونات الإضافية لمشروع postcss. يستبدل جميع القواعد الموجهة بقواعد متطابقة ويلفها في [dir="rtl"] . على سبيل المثال:


 /* input */ .foo { color: red; margin-left: 16px; } /* output */ [dir] .foo { color: red; } [dir="ltr"] .foo { margin-left: 16px; } [dir="rtl"] .foo { margin-right: 16px; } 

بعد ذلك ، ما عليك سوى تعيين dir="rtl" ويتم تطبيق القواعد الضرورية فقط تلقائيًا. كل شيء يعمل ويبدو أن كل شيء جاهز تقريبًا للإنتاج ، ولكن هذا الحل مناسب فقط لنموذج أولي سريع:


  • تزداد خصوصية كل قاعدة . لن تكون هذه مشكلة بالضرورة ، لكني أود تجنبها ؛
  • تؤدي مثل هذه التلاعبات إلى ظهور أخطاء . على سبيل المثال ، قد ينكسر ترتيب الخصائص ؛
  • حجم ملف css ينمو بشكل ملحوظ . [dir] إضافة [dir] إلى كل محدد ، ويتم تكرار كل خاصية موجهة. في حالتنا ، زاد الحجم في مشروع واحد بنسبة 21٪ ، وفي مشروع آخر - بنسبة 35٪:

الحجم الأصلي (gzip)الحجم ثنائي الاتجاه (gzip)متورم
2gis.ru272.3 كيلوبايت329.7 كيلوبايت21٪
m.2gis.ru24.5 كيلوبايت33.2 كيلوبايت35٪
habr.com33.1 كيلوبايت41.4 كيلوبايت25٪

هل هناك خيار أفضل؟


من الضروري جمع الأنماط لـ LTR و RTL بشكل منفصل. ثم لن يكون من الضروري لمس المحددات ولن يتغير حجم Css.


لهذا اخترت:


  1. RTLCSS - هذه المكتبة تحت غطاء postcss-rtl.
  2. webpack-rtl-plugin هو حل جاهز للأنماط التي بنيت من خلال ExtractTextPlugin. نفس RTLCSS تحت غطاء المحرك.

وبدأ في جمع RTL و LTR في ملفات مختلفة - styles.css و styles.rtl.css . النقص الوحيد في التجميع لملفات مختلفة هو أنه لا يمكنك استبدال dir على الفور دون تنزيل الملف المطلوب أولاً.


يتيح لك RTLCSS استخدام التوجيهات للتحكم في معالجة قواعد محددة ، على سبيل المثال:


 .foo { /*rtl:ignore*/ right: 0; } .bar { font-size:16px/*rtl:14px*/; } 

ما هي الحلول الأخرى الموجودة؟


جميع الحلول الحالية لا تختلف تقريبًا عن RTLCSS.


  • css-flip من تويتر ؛
  • cssjanus من ويكيميديا ​​؛
  • نعم ، ويدعم postcss-rtl المعلمة onlyDirection ، التي يمكنك من خلالها جمع الأنماط لاتجاه واحد فقط ، ولكن الحجم لا يزال ينمو - على سبيل المثال ، بالنسبة لنظام 2GIS للجوال فهو 18٪ بدلاً من 35٪ (24.5 كيلوبايت → 29 كيلوبايت).

متى تكون التوجيهات مطلوبة؟


عندما لا يجب أن تعتمد الأنماط على الاتجاه


على سبيل المثال ، زاوية دوران السهم تشير إلى اتجاه الريح:


الصورة
 .arrow._nw { /*rtl:ignore*/ transform: rotate(135deg); } 



أو يتلاشى رقم الهاتف - تتم كتابة الأرقام دائمًا من اليسار إلى اليمين ، مما يعني أن التدرج يجب أن يكون دائمًا على اليمين:


الصورة


الصورة


متى توسيط الرمز


هذه حالة خاصة من الفقرة السابقة. إذا قمنا بتوسيط الرمز غير المتماثل من خلال المسافة البادئة / تحديد الموضع ، فإننا نحول كتلته إلى الجانب ، وإذا كان يعكس الإزاحة ، فإن الرمز "يتحرك" إلى الجانب الآخر:


الصورة


من الأفضل توسيط الأيقونة في svg نفسها في مثل هذه المواقف:



عندما تحتاج إلى عزل عنصر واجهة مستخدم بالكامل لا يجب أن يستجيب لـ RTL


في حالتنا ، هذه خريطة. نلف جميع أنماطه عند التجميع في توجيهات الكتل: /*rtl:begin:ignore*/ ... /*rtl:end:ignore*/ .


هل هناك خيار أفضل؟


الحل مع عكس القواعد يعمل بشكل جيد ، ولكن السؤال الذي يطرح نفسه - هل هو عكاز؟ إن اعتماد الأنماط على الاتجاه هو مهمة طبيعية لشبكة الإنترنت الحديثة ، وتتزايد أهميتها كل عام. كان ينبغي أن ينعكس هذا في المعايير والمناهج الحديثة. ووجد!


الخصائص المنطقية


لتكييف التخطيط مع اتجاهات مختلفة ، هناك معيار للخصائص المنطقية في css . لا يتعلق الأمر فقط بالاتجاهات من اليسار إلى اليمين ومن اليمين إلى اليسار ، ولكن أيضًا الاتجاه من الأعلى إلى الأسفل ، ولكننا لن نفكر في ذلك.


نستخدم بالفعل شيئًا مشابهًا في الثنيات والشبكات - على سبيل المثال ، flex-start flex-end ، flex-start grid-row-start grid-column-end ، grid-column-end غير grid-column-end من اليسار / اليمين.


بدلاً من المفاهيم left right top bottom يُقترح استخدام inline-start و inline-end و block-start و block-end . بدلاً من width height - inline-size block-size . وبدلاً من اختصارات abcd - logical adcb المنطقي (الاختصارات المنطقية تذهب عكس اتجاه عقارب الساعة). أيضًا ، لإقران الاختصارات الحالية ، تظهر إصدارات مقترنة جديدة - padding-block ، margin-inline ، border-color-inline ، إلخ.


  • left: 0 → inset-inline-start: 0
  • padding-left: 4px → padding-inline-start: 4px
  • margin: 0 16px 0 0 → margin: logical 0 0 0 16px
  • padding-top: 8px; padding-bottom: 16px → padding-block: 8px 16px
  • margin-left: 4px; margin-right: 8px → margin-inline: 4px 8px
  • text-align: right → text-align: end

ويظهر الاختزال الذي طال انتظاره لتحديد المواقع:


  • left: 4px; right: 8px → inset-inline: 4px 8px
  • top: 8px; bottom: 16px → inset-block: 8px 16px
  • top: 0; right: 2px; bottom: 2px; left: 0 → inset: logical 0 0 2px 2px

هذا متاح بالفعل في فايرفوكس بدون أعلام وفي متصفحات الويب المستندة إلى العلم.


الإيجابيات - الحل أصلي ، سيعمل بدون تجميع / مكونات إضافية على الإطلاق ، إذا كانت المتصفحات المطلوبة مدعومة. ليست هناك حاجة إلى توجيهات - فقط اكتب left بدلاً من inline-start ، عندما تقصد "اليسار" المادي.


تأتي السلبيات من المحترفين - بدون مكونات إضافية ، فإن الرمز في معظم المتصفحات غير صالح ، تحتاج إلى القيام بالكثير من العمل لترجمة مشروع كبير موجود.


كيف تتصل؟


أسهل طريقة هي postcss-logical . بدون معلمة dir ، فإنه يجمع الأنماط لكلا الاتجاهين بنفس طريقة postcss-rtl ، مع معلمة dir المحددة ، فقط للاتجاه المحدد:


 .banner { color: #222222; inset: logical 0 5px 10px; padding-inline: 20px 40px; resize: block; transition: color 200ms; } /* becomes */ .banner { color: #222222; top: 0; left: 5px; bottom: 10px; right: 5px; &:dir(ltr) { padding-left: 20px; padding-right: 40px; } &:dir(rtl) { padding-right: 20px; padding-left: 40px; } resize: vertical; transition: color 200ms; } /* or, when used with { dir: 'ltr' } */ .banner { color: #222222; top: 0; left: 5px; bottom: 10px; right: 5px; padding-left: 20px; padding-right: 40px; resize: vertical; transition: color 200ms; } 

كيف تقنع فريقًا بالبدء في كتابة تعويض البداية المضمنة بدلاً من اليسار؟


مستحيل. لكننا قررنا في مشروعنا لتبسيطه - كتابة start: 0 بدلاً من offset-inline-start: 0 ، بمجرد أن يعتاد عليه ، سأبدأ في فرض إدخال صالح :)


RTL + CSS-in-JS = ️️ <3


لا يلزم تجميع CSS-in-JS مقدمًا. وهذا يعني أنه في وقت التشغيل ، من الممكن تحديد اتجاه المكونات واختيار العناصر التي سيتم قلبها وأيها لا. مفيد إذا كنت بحاجة إلى إدراج عنصر واجهة مستخدم لا يدعم RTL على الإطلاق.


بشكل عام ، تتمثل المهمة في تحويل كائنات من النوع { paddingInlineStart: '4px' } (أو { paddingLeft: '4px' } ، إذا لم يكن من الممكن التبديل إلى الخصائص المنطقية) إلى كائنات من النوع { paddingRight: '4px' } :


  1. تسليح باستخدام bidi-css-js أو rtl-css-js . أنها توفر وظيفة تأخذ كائن نمط وتعيد تحويلها إلى الاتجاه المطلوب.
  2. ؟؟؟
  3. ربح!

مثال للتفاعل


قم بلف كل مكون على نمط في HOC يقبل الأنماط:


 export default withStyles(styles)(Button); 

يأخذ اتجاه المكون من السياق ويختار الأنماط النهائية:


 function withStyles(styles) { const { ltrStyles, rtlStyles } = bidi(styles); return function WithStyles(WrappedComponent) { ... render() { return <WrappedComponent {...this.props} styles={this.context.dir === 'rtl' ? rtlStyles : ltrStyles} />; }; }; ... }; } 

ويركز المزود على السياق:


 <DirectionProvider dir="rtl"> ... <Button /> ... 

تستخدم Airbnb نهجًا مشابهًا: https://github.com/airbnb/react-with-styles-interface-aphrodite#built-in-rtl-support ، إذا تم استخدام أفروديت بالفعل في المشروع ، فيمكنك استخدام هذا الحل الجاهز.


بالنسبة إلى JSS ، لا يزال الأمر أسهل - ما عليك سوى تمكين jss-rtl :


 jss.use(rtl()); 

مكونات مصقولة


 const Button = styled.button` background: #222; margin-left: 12px; `; 

ماذا لو عملنا مع سلاسل القالب وليس مع الكائنات؟ كل شيء معقد ، ولكن هناك حل - احسب اسم الخاصية من الاتجاه المحدد في props :


 const marginStart = props => props.theme.dir === "rtl" ? "margin-left" : "margin-right"; const Button = styled.button` background: #222; ${marginStart}: 12px; `; 

ولكن يبدو من الأسهل التبديل من الخطوط إلى الكائنات ، فقد تمكنت المكونات ذات النمط من القيام بذلك منذ الإصدار 3.3.0 .


ميزات الترجمة والتعريب


اكتشفنا الجزء التقني. قاموا بعزل محتوى غير محدد الاتجاه ، وأنماط معكوسة ، ووضعوا استثناءات في الأماكن الصحيحة ، وترجموا النصوص إلى اللغة العربية. يبدو أن كل شيء جاهز - عند تبديل اللغة ، تظهر الواجهة بأكملها على الجانب الآخر من الشاشة ، ولا يوجد تخطيط في مكانه ويبدو كل شيء أفضل من أي موقع عربي.


نظهر العربي الحقيقي ، و ...


اتضح أن ليس كل متحدث عربي يعرف ما هو تويتر. ينطبق هذا على جميع الكلمات باللغة الإنجليزية تقريبًا. في مثل هذه الحالة ، هناك ترجمة عربية: "تويتر".


اتضح أنه في اللغة العربية هناك فواصل ، وحقيقة أننا في كل مكان في الكود تم ربطها من خلال "،" ، في اللغة العربية ، نحتاج إلى التسلسل من خلال "،".


اتضح أن التقويم الرسمي في بعض البلدان الإسلامية هو إسلامي. إنها قمرية ولا غنى عن صيغة الترجمة المعتادة.


اتضح أنه في دبي لا توجد درجة حرارة سلبية وأن علامة الجمع في توقعات +40 لا معنى لها.


ليس فقط التقاط الأنماط وعكسها


إذا فعلنا dir="auto" في عنصر الكتلة واتضح أن محتواه هو LTR ، فإن النص سيتفوق على الجانب الأيسر من الحاوية ، حتى إذا كان حول RTL. يمكن علاج هذا ببساطة عن طريق تعيين text-align: right بشكل صريح text-align: right . يمكنك حتى تطبيق ذلك على الصفحة الكاملة في النسخة العربية - قيمة هذه الخاصية موروثة.


لا تعكس الأيقونات تلقائيًا أيضًا. وبدون ذلك ، يمكن أن تبدو الرموز الاتجاهية ، مثل الأسهم الموجودة في المعرض ، في الاتجاه الخاطئ. تخيل أن هذه هي الحالة الوحيدة التي تبرر فيها الأسهم المصنوعة عبر الحدود نفسها!


سيساعد التحول البسيط على عكس الرموز:


 [dir="rtl"] .my-icon { transform: scaleX(-1); } 

صحيح أنه لن يساعد إذا كان الرمز يحتوي على أحرف أو أرقام. ثم عليك عمل رمزين مختلفين ولصقهما بشروط:


الصورة


ومع ذلك ، اتضح أنه ليس من الضروري عكس جميع عناصر الواجهة. على سبيل المثال ، في حالتنا ، قررنا ترك خانات الاختيار طبيعية:


الصورة


الصورة


لا أعرف كيفية تحديد هذه العناصر من الواجهة بالكامل. يمكن للمتحدث الأصلي فقط المساعدة هنا ، والذي سيقول ما هو مألوف لديه وما هو غير مألوف.


إدخال المستخدم


حتى إذا كنا نتحكم بشكل كامل في جميع بيانات تطبيقنا ، فيمكن أن يكون إدخال المستخدم. على سبيل المثال ، اسم الملف. يمكنك حتى إنشاء ملف .js وإعطائه كـ .png - كانت هذه الثغرة في Telegram :


cool_picture * U + 202E * gnp.js → cool_picture sj.png

في مثل هذه الحالات ، يجدر تصفية أحرف utf غير اللائقة من السلسلة.


تقليب النصوص


يتغير بناء الجملة قليلاً في جافا سكريبت RTL. الحلقة التي بدت هكذا:


 for (let i = 0; i < arr.length; i++) { 

الآن تحتاج إلى كتابة مثل هذا:


 for (++i; length.arr > i; let 0 = i) { 

مزحة.


كل ما عليك فعله هو تجنب مفهومي "اليسار" و "الأيمن" في التعليمات البرمجية الخاصة بك. على سبيل المثال ، واجهنا مشاكل في حساب إحداثيات مركز الشاشة - قبل تعليق جميع البطاقات على اليسار ، والآن على اليمين ، ولكن رمز التطبيق لم يكن يعرف عنها. يجب إجراء جميع الحسابات والأنماط المضمنة ، مع مراعاة التركيز الأساسي.


خفة دم سريعة


في بعض الحالات ، يكون من الصعب تنفيذ دعم RTL في بعض مكونات النظام. ثم تحتاج إلى محاولة تكييف هذا المكون مع RTL من الخارج ، ولكن اترك LTR في الداخل.


على سبيل المثال ، لدينا شريط تمرير. يدعم القيم المرتبة الإيجابية فقط. يمكن أن يكون خطيًا ولوغاريتميًا (في البداية ، تكون كثافة القيم أقل من النهاية). تحتاج إلى عكس ذلك مع الحفاظ على سلوك المقياس.


الصورة


يمكنك قلب المنزلق باستخدام transform: scaleX(-1) . ثم عليك عكس العمل باستخدام الماوس (النقرات والسحب) بالنسبة لمركز شريط التمرير. خيار سيئ.


هناك خيار آخر - لتدوير المحور في الاتجاه الآخر ، وتغيير فقط نقل القيم واستلامها من شريط التمرير. إذا كان هذا مقياسًا خطيًا ، فبدلاً من مجموعة القيم [10 ، 100 ، 1000] ، سننقل المجموعة [N-1000 ، N-100 ، N-10] ، وفي المعالج سوف نعيدها مرة أخرى. بالنسبة للمقياس اللوغاريتمي ، بدلاً من المجموعة [10 ، 100 ، 1000] ، نمر [1/1000 ، 1/100 ، 1/10]:


 function flipSliderValues(values, scale, isRtl) { if (!isRtl) { return values; } if (scale === 'log') { // [A, B] --> [1/B, 1/A] return values.map(x => 1 / x).reverse(); } // [A, B] --> [MAX-B, MAX-A] return values.map(x => Number.MAX_SAFE_INTEGER - x).reverse(); }; 

هذه هي الطريقة التي بدأ بها شريط التمرير لدعم RTL ، على الرغم من أنه هو نفسه لا يعرف ذلك.


قصة


على النقيض من التنضيد تحت بعض IE9 ، لا تحتاج إلى تشغيل متصفح منفصل للتحقق من التنضيد تحت RTL. يمكنك حتى كتابة ورؤية تخطيط LTR و RTL في وقت واحد في نافذة واحدة. للقيام بذلك ، يمكنك ، على سبيل المثال ، إنشاء مصمم في كتاب القصة ، والذي يجعل نسختين من القصة في وقت واحد:


الصورة


تُظهر لقطة الشاشة أنه بدون text-overflow: ellipsis لا يتصرف text-overflow: ellipsis كما نرغب - فمن الأفضل إصلاحه على الفور.


من الأسهل بكثير دعم RTL على الفور أثناء التخطيط بدلاً من اختبار المشروع بالكامل على الإطلاق لاحقًا.


مشاكل غير محلولة


معرفة النظرية لا تساعد على حل جميع المشاكل على الإطلاق. سأعطي مثالا واحدا.


تلميح يظهر في اتجاه النص أثناء الكتابة. عندما نتحدث عن الإدخال متعدد اللغات ، لا يمكننا أن نعرف مقدمًا الاتجاه الذي يتم عرض هذه المطالبة فيه:




تحتاج إلى محاولة تجنب مثل هذه المشاكل في مرحلة التصميم وأحيانًا التخلي عن الحلول الواضحة لـ LTR وغير القابلة للتطبيق في RTL. في هذه الحالة ، عند التنقل في المطالبات ، يمكنك استبدال النص بالكامل (كما تفعل Yandex أو Google على سبيل المثال).


الاستنتاجات


RTL ليس مجرد "قلب كل شيء"


من الضروري أن تأخذ في الاعتبار خصوصيات اللغة ، لا تحتاج إلى قلب شيء ما ، تحتاج إلى تكييف شيء آخر. في مكان ما من المنطق ، من الضروري للغاية التخلي عن "اليمين" / "اليسار".


من الصعب جدًا القيام بشيء ما دون معرفة اللغة


ستعتقد أن كل شيء جاهز حتى تعرض مشروعك على متحدث أصلي حقيقي. تطور من وجهة نظر شخص لا يعرف أي لغة. بعد كل شيء ، حتى هذه الكلمات الواضحة بالنسبة لك ، مثل ، على سبيل المثال ، "Twitter" ، قد يتعين ترجمتها. وتبين أن علامات الترقيم ليست هي نفسها على الكوكب بأكمله.


الوصفة النهائية


من الصعب وصف كل شيء تمت مناقشته في مقالتين في قائمة واحدة. لن يكون هناك تجول ، ولكن إليك الشيء الرئيسي الذي يجب القيام به:


  • تأكد من العثور على متحدث أصلي وأريه النماذج الأولية في أقرب وقت ممكن ؛
  • اجمع أنماط LTR و RTL في ملفات مختلفة. لهذا ، فإن rtlcss و webpack-rtl-plugin مناسبان ؛
  • أضف استثناءات لكل ما لا يحتاج إلى تسليم وعكس بوضوح ما لم يسلم نفسه ؛
  • عزل كل المحتوى التعسفي باستخدام <bdi> و dir="auto" ؛
  • تعيين text-align بشكل صريح إلى الصفحة بأكملها ؛
  • تجنب left / right في كود شبيبة عندما تقصد البداية والنهاية.

استعد لقضاء معظم الوقت في أصغر التفاصيل.


ليس من الصعب الاستعداد مسبقًا


وبعض النصائح لأولئك الذين لن يقوموا بتكييف الموقع مع RTL حتى الآن ، لكنهم يريدون وضع قشة:


  • لا تستخدم خاصية direction لأغراض أخرى ؛
  • فقط في حالة استمرار عزل جميع المحتوى التعسفي (وفي الواقع ، حتى في واجهة اللغة الإنجليزية ، يمكن للمستخدمين كتابة شيء باللغة العربية وكسر كل شيء) ؛
  • استخدم خصائص css المنطقية إن أمكن ؛
  • تحقق من التخطيط ليس فقط في المتصفحات المختلفة ، ولكن أيضًا في بعض الأحيان في RTL ، على الأقل من أجل الفضول. يتحكم بشكل أفضل بشكل غير ملحوظ في التخطيط تحت RTL باستخدام أدوات مثل كتاب القصة ؛
  • لا تسمح ببناء لغة الكود الصلب (على سبيل المثال ، سلسلة من السلاسل مفصولة بفواصل) ، إن أمكن ، قم بتكوين كل شيء ، بما في ذلك علامات الترقيم. هذا مفيد ليس فقط ل RTL - على سبيل المثال ، في اليونانية علامة الاستفهام هي "؛".

لا ينبغي أن تكون هذه القواعد من المتاعب. ولكن إذا جاءت فجأة الرغبة في إطلاق إصدار RTL ، فستصبح أرخص بكثير مما يمكن.

Source: https://habr.com/ru/post/ar416635/


All Articles