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

لطالما أردت أن أشارك أفكاري وخبراتي ... وبالطبع الحديث عن الحياة.
قبل التاريخمن الواضح أن حلول إدارة النصوص والتوطين موجودة بالفعل ، لكنها لم تناسبني لأسباب مختلفة: لا تتوافق مع مرونتي ، غير مناسب للاستخدام ، غير مناسبة ، مع رؤيتي لحل هذه المشكلة ، تفتقر إلى الوظيفة.
بالإضافة إلى ذلك ، لا أحب المكتبات الخارجية حقًا بسبب ميلها إلى النمو (وهذا هو عندما نحتاج فقط إلى جزء صغير من جميع الوظائف).
الشركة التي أعمل بها لها حلها الخاص ، لكنها في رأيي أبعد ما تكون عن المثالية. والحاجة إلى التوافق مع الإصدارات القديمة مع الإصدارات تجعل الأمر معقدًا بشكل غير ضروري.
في مرحلة ما ، أردت شيئًا بسيطًا وسهلاً ومفهومًا وقابل للتوسيع بلا حدود لمهام مختلفة.
بيان المشكلة
يبدو أن كل شيء واضح هنا. أم لا؟ دعونا نفكر في ما نود.
نحن بحاجة إلى الحصول على نصوص مترجمة بطريقة أو بأخرى. قد تحتوي النصوص على متغيرات. هل يمكن ترجمة المتغيرات أيضًا؟! من الناحية النظرية ، نعم. وإذا كان المتغير هو تاريخ أم رقم؟! بالإضافة إلى دعم تخفيض السعر. وأخيرا ، بعض الحلول في حالة عدم العثور على النص.
تطبيق
سيكون الأساس كائنًا بسيطًا ، حيث يكون المفتاح هو رمز النص ، وتكون القيمة هي النص الفعلي الذي تحتاجه ، لا شيء معقد:
const textsBundle = { 'button.open': 'Open', 'button.save': 'Save', }; function TextManager(texts) { this.getText = function(code) { return texts[code]; }; } const textManager = new TextManager(textsBundle); textManager.getText('button.open');
قليلا عن اسم المفاتيحاسم المفاتيح هو موضوع منفصل. من الأفضل الموافقة فورًا على خيار واحد ، وإلا فإن المفاتيح المختلفة "ستثير" :). لا يوجد حل واحد ، اختر ما تعتقد أنه أكثر ملاءمة وأكثر اتساقًا مع المشروع. أنا شخصياً أحب الأول:
'button.open.label'
'button.open.help_text'
أو
'button.label.open'
'button.help_text.open'
أو
'label.button.open'
'help_text.button.open'
بعد ذلك ، نحتاج إلى آلية يمكنها إجراء نوع من المعالجة مع النص قبل أن يعطي النتيجة النهائية ، على سبيل المثال ، إدراج معلمات. ثم حصلت على فكرة مثيرة للاهتمام - ماذا لو استخدمنا الوسيطة لمعالجة النص؟ بعد كل شيء ، لم أر مثل هذه القرارات ... حسنًا ، أو نظرت بشكل سيء :)
نحن نقرر متطلبات الوسيطة: عند الإدخال ، تقبل الوسيطة النص والمعلمات ، وستعط النص الناتج ، بعد التلاعب اللازم.
ستتلقى البرامج الوسيطة الأولى النص الأصلي ، بينما ستتلقى النصوص التالية النص من الوسيطة السابقة. دعنا نضيف الكود المفقود:
function TextManager(texts, middleware) { function applyMiddleware(text, parameters, code) { if (!middleware) return text; return middleware.reduce((prevText, middlewareItem) => middlewareItem(prevText, parameters, code), text); } this.getText = function(code, parameters) { return applyMiddleware(texts[code], parameters, code); }; }
يمكن TextManager إخراج النص عن طريق الرمز الخاص به. يمكن أيضًا توسيعه باستخدام برنامج الوسيطة ، والذي يفتح العديد من الاحتمالات ، على سبيل المثال:
- معالجة الحالة عندما لا يتم العثور على النص
- استخدام المعلمات في النص
- توطين المعلمة
- استخدام تخفيض السعر
- التدريع النص ، الخ
ممارسة
سنكتب بضع الوسيطة اللازمة. سوف تحتاج إليها 100 ٪.
InsertParams
يسمح باستخدام المعلمات في النصوص. على سبيل المثال ، نحتاج إلى عرض النص "مرحبًا {{اسم المستخدم}}". توفر الوسيطة التالية هذا:
function InsertParams(text, parameters) { if (!text) return text; if (!parameters) return text; let nextText = text; for (let key in parameters) { if (parameters.hasOwnProperty(key)) { nextText = text.replace('{{' + key + '}}', parameters[key]); } } return nextText; }
UseCodeIfNoText
يتيح لك إرجاع رمز النص ، بدلاً من عدم undefined
، إذا لم يتم العثور على النص:
function UseCodeIfNoText(text, parameters, code) { return text ? text : code; }
الإجمالي نتلقى الاستخدام التالي تقريبا:
const textsBundle = { 'text.hello': 'Hello', 'text.hello_with_numeric_parameter': 'Hello {{0}}', 'text.hello_with_named_parameter': 'Hello {{username}}', }; const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); textManager.getText('nonexistent.code')
رد مثال التطبيق
أولاً ، التهيئة في المستوى الأعلى TextManager
وإضافة النصوص.
في رأيي ، من الأفضل سحب النصوص من الخادم ، ولكن من أجل البساطة لن أفعل ذلك.
const textsBundle = { 'text.hello': 'Hello {{username}}' } function TextManagerProvider({ children }) { const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); return ( <TextManagerContext.Provider value={textManager}> {children} </TextManagerContext.Provider> ) }
بعد ذلك ، في المكون ، نستخدم textManager
، على سبيل المثال ، باستخدام خطاف ، ونحصل على النص المطلوب عن طريق الرمز.
function SayHello({ username }) { const textManager = useContext(TextManagerContext); return ( <div> {textManager.getText('text.hello', { username })} </div> ) }
التعريب
أنت تسأل ، "ما علاقة التوطين به؟".
كل شيء بسيط للغاية - عند تغيير اللغة وإنشاء مثيل جديد من TextManager
وإضافة النصوص والحصول على النتيجة على الفور.
الفصل قبل الأخير :)
كما ترى من الأمثلة ، فإن الاستخدام بسيط للغاية ، وبفضل البرامج الوسيطة يمكنك توسيع الوظيفة إلى أجل غير مسمى.
لقد نشرت تطبيقي على جيثب وأخطط لتطوير مدير النصوص . استخدام ، وتقديم التحسينات ، وكما يقولون هناك ، اهلا وسهلا بكم! :)
في الختام
لذا فقد استوفيت رغبتي في daaaaavnee - كتب مقالة عن هبر. آمل حقًا أن تكون هذه المقالة مفيدة وسوف ترضي المجتمع.
شكرا لاهتمامكم