Arabic build टूटा हुआ दिखता है, जबकि translation सही होती है। Sidebar बाईं ओर रहता है, back arrow बाईं ओर इशारा करता है और avatar हर card के बाएँ किनारे से चिपका रहता है—हर शब्द अरबी है, लेकिन हर box वहीं है जहाँ English version ने उसे रखा था। Text direction एक HTML attribute और components में मौजूद CSS decisions का संयोजन है; कोई catalog file इसे अपने साथ नहीं रखती। globalize.now AI-powered localization infrastructure है, जो strings extract करता है और हर Git push पर catalogs को sync रखता है।
Arabic में मेरा Lovable app अब भी left-to-right क्यों दिखता है?
क्योंकि direction document और stylesheet की property है, message की नहीं।
आपके catalogs source strings और translated strings की जोड़ियाँ हैं। जब वे ar के लिए compile होकर आपके components में render होती हैं, तो शब्द बदलते हैं और कुछ नहीं। चाहे catalogs Lingui के हों, जिनमें globalize.now लिखता है, या react-i18next के—यहाँ कोई अंतर नहीं पड़ता। किसी भी format में यह बताने की जगह नहीं होती कि “sidebar दूसरी ओर चला जाए।”
दो चीज़ें बदलनी होंगी। html element पर मौजूद dir attribute browser को बताता है कि inline axis किस दिशा में चले। आपके CSS को sides के नाम लेने के बजाय उस axis के start और end के नाम लेने होंगे। बाकी सब इन्हीं दो बदलावों से तय होता है।
Lovable app में Arabic जोड़ने पर वास्तव में क्या टूटता है?
समस्याएँ कुछ अनुमानित जगहों पर दिखाई देती हैं और ये सभी copy की नहीं, styling की समस्याएँ हैं।
- Navigation drawers और sidebars physical left पर ही बने रहते हैं।
- Chevrons, back arrows और progress indicators गलत दिशा में इशारा करते हैं।
- Asymmetric padding content को गलत किनारे से चिपका देती है, इसलिए labels एक ओर भीड़ जाते हैं।
- Heading पर
text-leftArabic को उसके container के बाएँ हिस्से में ही pinned रखता है। - Absolutely positioned badges और close buttons उस कोने के विपरीत पहुँचते हैं जहाँ reader उन्हें देखने की अपेक्षा करता है।
- Active list item को चिह्नित करने वाले left borders leading edge के बजाय trailing edge पर दिखाई देते हैं।
- Arabic sentence के भीतर English product code, direction hint के बिना अप्रत्याशित ढंग से reorder हो जाता है।
इनमें से कोई भी translation defect नहीं है। हर समस्या class name में hardcode की गई physical direction के कारण है।
Locale tag से text direction कैसे निकालूँ?
Locale से पूछें कि वह किस direction का इस्तेमाल करता है, फिर उस उत्तर को document पर लिख दें।
Intl.Locale.prototype.getTextInfo() किसी locale tag के लिए ltr या rtl में से एक direction लौटाता है। जुलाई 2026 में इसे Baseline newly available status मिला, यानी यह हर core browser के मौजूदा version में आ चुका है, लेकिन आपके users द्वारा इस्तेमाल किए जा रहे अधिकांश browsers में अभी नहीं है। नीचे दिए गए fallback को live path मानें और API को ऐसा समाधान समझें जिसे अंततः हटाया जा सकेगा।
// getTextInfo() is not yet in TypeScript's bundled Intl.Locale definitions.
declare global {
namespace Intl {
interface Locale {
getTextInfo?(): { direction: "ltr" | "rtl" };
}
}
}
// Stopgap for runtimes without getTextInfo(). This set is the one place where
// adding a new right-to-left language still costs you a code change.
const RTL_FALLBACK = new Set([
"ar", "he", "fa", "ur", "ps", "sd", "yi", "dv", "ckb", "ug", "nqo", "syr",
]);
export function directionFor(locale: string): "ltr" | "rtl" {
let tag: Intl.Locale | undefined;
try {
tag = new Intl.Locale(locale);
} catch {
// Malformed tag. Fall through to the string path below.
}
const direction = tag?.getTextInfo?.().direction;
if (direction === "ltr" || direction === "rtl") return direction;
const language = tag?.language ?? locale.split(/[-_]/)[0].toLowerCase();
return RTL_FALLBACK.has(language) ? "rtl" : "ltr";
}
The two try sites matter. new Intl.Locale() throws a RangeError on a malformed tag, and getTextInfo() is simply missing on older runtimes. Handling only the second is the usual bug: a locale like ar_EG arriving from a query string sends the function into its own recovery path and straight back out again as an uncaught error.
जहाँ भी आपका app active locale को पहले से जानता है, वहाँ दोनों attributes सेट करें। Lovable अभी दो तरह के projects scaffold करता है: Vite single-page app और server-rendered TanStack Start app। इसलिए पहले जाँचें कि आपके project ने वास्तव में क्या generate किया है। TanStack Start में यह root document component होता है। Vite में यह वह जगह होती है जहाँ आप i18n provider mount करते हैं।
<html lang={locale} dir={directionFor(locale)}>
html पर dir लगाएँ, किसी wrapper div पर नहीं। Portals, modals और toasts आपके component tree के बाहर render होते हैं और उन्हें भी यह inherit करना होता है।
Right-to-left के लिए मुझे कौन-सी Tailwind classes बदलनी होंगी?
वे classes जो physical side का नाम बताती हैं। उनके logical equivalents inline axis का अनुसरण करते हैं और dir बदलने पर अपने-आप flip हो जाते हैं।
| Physical utility | Logical replacement | यह क्या सेट करता है |
|---|---|---|
| ml-4 / mr-4 | ms-4 / me-4 | margin-inline-start / margin-inline-end |
| pl-6 / pr-6 | ps-6 / pe-6 | padding-inline-start / padding-inline-end |
| left-0 / right-0 | start-0 / end-0 | inset-inline-start / inset-inline-end |
| text-left / text-right | text-start / text-end | inline-axis text alignment |
| border-l / border-r | border-s / border-e | आरंभिक / अंतिम बॉर्डर |
| rounded-l-lg / rounded-r-lg | rounded-s-lg / rounded-e-lg | आरंभिक / अंतिम कोने |
| float-left / float-right | float-start / float-end | इनलाइन अक्ष पर फ्लोट |
| clear-left / clear-right | clear-start / clear-end | इनलाइन अक्ष पर क्लियर |
| scroll-ml-4 / scroll-mr-4 | scroll-ms-4 / scroll-me-4 | स्क्रॉल-स्नैप मार्जिन |
Tailwind का मार्जिन दस्तावेज़ सीधे प्रभाव दिखाता है: ms-8 और me-8, dir="ltr" और dir="rtl" कंटेनरों के भीतर रेंडर होकर विपरीत किनारों पर बैठते हैं। लॉजिकल प्रॉपर्टी यूटिलिटी Tailwind v3.3 में आई थीं, इसलिए लंबे समय से चल रहे प्रोजेक्ट में वे उपलब्ध न हों।
दो यूटिलिटी को नाम बदलने के बजाय दोबारा जाँचने की ज़रूरत है। space-x-* और divide-x-* सिब्लिंग्स के बीच स्पेसिंग और बॉर्डर जोड़ते हैं, इसलिए रिवर्स्ड रो में वे हर चाइल्ड की गलत तरफ पहुँच जाते हैं। Tailwind इसी स्थिति के लिए space-x-reverse और divide-x-reverse देता है। mt-* और pb-* जैसी वर्टिकल यूटिलिटी में बदलाव की ज़रूरत नहीं, क्योंकि दिशा केवल इनलाइन अक्ष को नियंत्रित करती है।
लॉजिकल प्रॉपर्टी क्या ठीक नहीं कर सकतीं?
बॉक्स मॉडल के बाहर की दिशा को एन्कोड करने वाली हर चीज़—यहीं rtl: और ltr: वेरिएंट उपयोगी साबित होते हैं।
<ChevronRight className="rtl:rotate-180" />
<div className="bg-[url(/hero.svg)] bg-left rtl:bg-right" />
<div className="shadow-[4px_0_8px_rgba(0,0,0,.15)] rtl:shadow-[-4px_0_8px_rgba(0,0,0,.15)]" />
ट्रांसफ़ॉर्म, बैकग्राउंड पोज़िशन, शैडो ऑफ़सेट, ग्रेडिएंट एंगल, कैरोसेल का स्क्रॉल गणित और “आगे” का अर्थ बताने वाले आइकन इसी श्रेणी में आते हैं। सूची छोटी रखें। हर दूसरे एलिमेंट पर rtl: लिखना बताता है कि मूल स्टाइल अब भी फिजिकल हैं और उन्हें इसके बजाय कन्वर्ट किया जाना चाहिए।
यूज़र-जनरेटेड कंटेंट के लिए अलग हैंडलिंग चाहिए, और दोनों मामले अलग हैं। जिस पूरे ब्लॉक की भाषा पर आपका नियंत्रण नहीं है, उसमें dir="auto" ब्राउज़र को पहले मज़बूत कैरेक्टर के आधार पर ब्लॉक की मूल दिशा तय करने देता है।
<p dir="auto">{review.body}</p>
पहले से दिशा-निर्धारित वाक्य के भीतर किसी विदेशी-लिपि वाले अंश के लिए—जैसे अरबी बॉडी टेक्स्ट में मौजूद अंग्रेज़ी SKU—dir="auto" कुछ नहीं करता, क्योंकि यह पैराग्राफ़ की मूल दिशा तय करता है, इनलाइन अंश को अलग नहीं करता। उस अंश को अलग से रैप करें।
<bdi>{product.sku}</bdi>
ट्रांसलेशन विजेट आपके लिए लेआउट को फ़्लिप क्यों नहीं कर सकता?
क्योंकि विजेट रेंडर किए गए पेज के टेक्स्ट नोड्स पर काम करता है, जबकि आपकी दिशा की समस्या उन स्टाइल में होती है जिनसे वह पेज बना है।
रनटाइम सर्विस दस्तावेज़ पर dir="rtl" जोड़ सकती है और अंग्रेज़ी वर्ज़न के रेंडर होने के बाद दिखाई देने वाली स्ट्रिंग्स का अनुवाद कर सकती है। लेकिन वह आपके कंपोनेंट खोलकर ml-4 को ms-4 में नहीं बदल सकती, क्योंकि ml-4 पहले ही ऐसी स्टाइलशीट में margin-left में कंपाइल हो चुका है जिसका स्वामित्व उस सर्विस के पास नहीं है। नतीजा होता है: बाएँ-से-दाएँ लेआउट के भीतर अरबी टेक्स्ट।
इसकी एक दूसरी कीमत भी है। कुछ Lovable ऐप्स में इस्तेमाल होने वाली रनटाइम ट्रांसलेशन सर्विस Lovalingo ने घोषणा की है कि वह 31 अगस्त 2026 को 23:59 CEST पर बंद हो जाएगी। उसकी माइग्रेशन गाइड ग्राहकों को प्रोजेक्ट-स्वामित्व वाले अंतर्राष्ट्रीयकरण पर जाने और इसे हटाने से पहले locale routes, canonical URLs और hreflang की दोबारा जाँच करने को कहती है। किसी वेंडर के प्रोडक्ट के भीतर किया गया लेआउट कार्य वेंडर के साथ ही चला जाता है। आपकी अपनी रिपॉज़िटरी में मौजूद लॉजिकल यूटिलिटी और dir एट्रिब्यूट नहीं जाते। हमारी Lovalingo तुलना स्ट्रिंग लेयर के बारे में भी यही तर्क देती है।
अगला Lovable प्रॉम्प्ट इसे फिर से बिगाड़ न दे, इसके लिए क्या करें?
एक बार कन्वर्ट करें, फिर रिव्यू में फिजिकल यूटिलिटी को दिखाई देने योग्य बना दें।
- वर्कफ़्लो इंस्टॉल करें। Lovable वर्कस्पेस में
lovable-i18nस्किल जोड़ें और Lovable को i18n सेट अप करने का प्रॉम्प्ट दें। एडिटर के बाहर इंस्टॉलेशनnpx skills add globalize-now/globalize-skillsहै, और हर एजेंट के लिए इंस्टॉल करने हेतु--allका इस्तेमाल करें। - ऊपर दिए गए
directionForका इस्तेमाल करके,htmlएलिमेंट पर locale के आधार पर दिशा सेट करें। - अपने कंपोनेंट्स में फिजिकल यूटिलिटी को लॉजिकल यूटिलिटी में कन्वर्ट करें—शुरुआत उन कंपोनेंट्स से करें जो आपके पेजों को रैप करते हैं।
- ट्रांसफ़ॉर्म, बैकग्राउंड, शैडो और दिशात्मक आइकन के लिए ही
rtl:वेरिएंट जोड़ें, और इनलाइन विदेशी-लिपि वाले अंशों के लिए<bdi>का इस्तेमाल करें। - रिव्यू में एक grep gate जोड़ें, ताकि नई जनरेट हुई फिजिकल यूटिलिटी मर्ज होने से पहले ही फ़ेल हो जाए।
rg -n '\b(ml|mr|pl|pr|scroll-m[lr])-|\b(float|clear|text)-(left|right)\b|\bborder-[lr]\b|\brounded-[lr]-|\b(left|right)-[0-9]' src/
पाँचवाँ चरण ही टिकाऊ समाधान है। Lovable हर प्रॉम्प्ट पर कंपोनेंट्स दोबारा जनरेट करता है, और सेटिंग्स पैनल जोड़ने को कहा जाए तो मॉडल ml-4 का इस्तेमाल करेगा, क्योंकि जिन React कोड पर इन मॉडलों को प्रशिक्षित किया गया है उनमें फिजिकल यूटिलिटी का बोलबाला है। पुल रिक्वेस्ट को फ़ेल करने वाली जाँच, तीन हफ़्ते बाद अरबी स्क्रीनशॉट में समस्या ढूँढने से कहीं सस्ती है।
लूप का स्ट्रिंग वाला हिस्सा अपने-आप चलता है। globalize.now Lovable द्वारा जनरेट किए गए कोड से नई हार्डकोडेड स्ट्रिंग्स निकालता है, उन्हें आपके कैटलॉग में लिखता है और हर Git push पर सिंक करता है। इसलिए आप प्रॉम्प्ट करते रहें और अरबी बिल्ड अपडेटेड रहे। यही मैकेनिज़्म Vite गाइड और TanStack Start गाइड में बताया गया है, और इसी वजह से हर push पर translations टूटना बंद हो जाता है।
प्लान में अरबी जोड़ने का कोई अतिरिक्त शुल्क नहीं है। Starter प्लान की कीमत प्रति वर्कस्पेस €20 प्रति माह है, जिसमें €20 का translation credit (लगभग 200,000 शब्द) शामिल है। उसके बाद भी उपयोग उसी प्रति-कैरेक्टर दर पर जारी रहता है—न प्रति-सीट शुल्क, न प्रति-भाषा शुल्क—और दाएँ-से-बाएँ लिखी जाने वाली भाषाएँ भी शामिल हैं। सेटअप की अधिक जानकारी Lovable integration पेज पर, इंजीनियरिंग विवरण developers पेज पर और गैर-तकनीकी बिल्डर्स के लिए छोटा रास्ता vibe coders पेज पर है।
एक लेआउट बदलाव, फिर यह हमेशा ठीक रहता है
दिशा का निर्णय आपकी रिपॉज़िटरी एक बार लेती है। हर बार प्रॉम्प्ट करने पर बदलने वाला हिस्सा स्ट्रिंग्स हैं—और वह हिस्सा अपने-आप चलता है।
globalize.now आपके ऐप्लिकेशन की हार्डकोडेड कॉपी को अनुवाद-तैयार locale फ़ाइलों में बदल देता है और जैसे-जैसे आप नई रिलीज़ करते हैं, उन्हें अपडेट रखता है।
globalize.now को निःशुल्क आजमाएं