بین الاقوامی زبانوں کی معاونت
دائیں سے بائیں اور مخلوط سمت کا متن، عربی حروف کی شکل بندی، اور فوکس پیڈ کا ترجمہ۔
Text.js عبرانی، عربی، فارسی اور دائیں سے بائیں لکھے جانے والے دوسرے رسم الخط DevTools، ٹرمینلز اور DOM مررز میں درست ترتیب سے، سیل گرڈ کے مطابق رینڈر کرتا ہے۔ یہ Unicode Bidirectional Algorithm (UAX #9، Unicode 18.0) نافذ کرتا ہے اور مطابقت کے سرکاری ٹیسٹ سوئٹس پاس کرتا ہے: BidiTest.txt کے تمام 770,241 کیسز (ہر پیراگراف سمت میں ہر ان پٹ) اور BidiCharacterTest.txt کے تمام 91,707 کیسز۔
import { Box, Text } from "@textjs/react";export default function Page() { return ( <Box flexDirection="column" padding={1}> <Text>שלום עולם! זהו טקסט בעברית.</Text> <Text>مرحبا بالعالم! هذا نص عربي.</Text> <Text>Order #1234 (<Text color="accent">שלום</Text>) total: 25.50 ₪</Text> <Text>user <Text dir="auto" color="success">שלום!</Text> replied 3 times</Text> </Box> );}سمت
ہر پیراگراف (<Text> کی ہر وہ لائن جو \n سے الگ ہو) اپنے پہلے مضبوط کریکٹر سے اپنی بنیادی سمت چنتا ہے، جیسے HTML میں dir="auto" کرتا ہے۔ دائیں سے بائیں پیراگراف ڈیفالٹ طور پر دائیں جانب سیدھ میں ہوتے ہیں۔
<Text>שלום</Text> {/* auto: RTL, right-aligned */}<Text dir="rtl">hello!</Text> {/* "!hello", right-aligned */}<Text dir="ltr">שלום!</Text> {/* LTR paragraph: "םולש!" reads correctly left of the "!" */}<Text align="left">שלום</Text> {/* RTL order, pinned to the left edge */}align | بائیں سے دائیں پیراگراف | دائیں سے بائیں پیراگراف |
|---|---|---|
"start" (ڈیفالٹ) | بائیں | دائیں |
"end" | دائیں | بائیں |
"left" / "center" / "right" | جیسا لکھا ہے | جیسا لکھا ہے |
نیسٹڈ <Text> پر dir، HTML کے <bdi> کی طرح span کو الگ کرتا ہے: اس کے مواد کا لے آؤٹ الگ بنتا ہے اور وہ آس پاس کے متن کی ترتیب نہیں بدل سکتا۔ صارف کے فراہم کردہ ناموں، عنوانات اور نامعلوم سمت والے دوسرے متن کے لیے اسے استعمال کریں۔
<Text>user <Text dir="auto">{name}</Text> replied 3 times</Text>// name = "שלום!" → user !םולש replied 3 times (isolated: "!" ends the name)// without dir → user םולש! replied 3 times ("!" resolves with the Latin text around it)رینڈرنگ کا طریقہ
- منطقی ترتیب میں ریپ کریں۔ لائنیں سیل کی چوڑائی کے مطابق بالکل اسی طرح ٹوٹتی ہیں جیسے بائیں سے دائیں متن میں۔
- ہر لائن کی ترتیب بدلیں۔ الگورتھم پورے پیراگراف کے ایمبیڈنگ لیولز طے کرتا ہے (واضح ایمبیڈنگز اور آئسولیٹس، کمزور اور نیوٹرل اقسام، جوڑی والے بریکٹس)، پھر ہر ریپ شدہ لائن کی ترتیب الگ بدلتی ہے (قواعد L1–L2)۔ دائیں سے بائیں لیولز پر بریکٹس اور عکس والے دوسرے کریکٹر بدل جاتے ہیں (L4)، اس لیے عبرانی کے اندر
(abc)،(abc)ہی رہتا ہے۔ - عربی کی شکلیں بنائیں۔ حروف اپنی سیاقی شکلیں (الگ، ابتدائی، درمیانی، آخری) Arabic Presentation Forms بلاکس سے لیتے ہیں، جن کا حساب لائن کے ہر لیول رن میں منطقی ترتیب سے ہوتا ہے (ZWJ اور ZWNJ اپنی جگہ پر شمار ہوتے ہیں)۔ ایک حرف ایک سیل ہے، جڑی ہوئی شکلیں کسی بھی span کی حد (کرسر، رنگ کی تبدیلی) پر برقرار رہتی ہیں، اور کونسول کو کبھی ان کی شکلیں نہیں بنانی پڑتیں۔
- ترتیب مقرر کریں۔ اب سیلز میں گلف ڈسپلے کی ترتیب میں ہیں۔ براؤزر اور بہت سے ٹرمینلز ان پر دوسری بار bidi چلائیں گے، اس لیے ڈرائیور ترتیب لاک کرتے ہیں:
| آؤٹ پٹ | ترتیب مقرر کرنے کا طریقہ |
|---|---|
DevTools (CssConsoleDriver) | دائیں سے بائیں کریکٹرز والے spans کو LRO … PDF (U+202D / U+202C) میں لپیٹا جاتا ہے۔ DevTools کا %c سینیٹائزر direction اور unicode-bidi ہٹا دیتا ہے۔ |
ٹرمینلز (AnsiDriver، text run) | دائیں سے بائیں متن والی قطاریں ان ٹرمینلز کے لیے LRO … PDF میں لپیٹی جاتی ہیں جو ہر لائن پر bidi چلاتے ہیں۔ renderToTerminal داخلے پر ایک بار ECMA-48 BDSM کے واضح موڈ (CSI 8 l، جس کی VTE پر مبنی ٹرمینلز پیروی کرتے ہیں) میں اور اخراج پر واپس ضمنی موڈ (CSI 8 h) میں بدلتا ہے؛ دائیں سے بائیں متن والے یک وقتی renderToAnsi فریم CSI 8 l سے شروع ہوتے ہیں۔ سیلز جوں کے توں آؤٹ پٹ کرنے کے لیے bidi: "none" پاس کریں۔ |
DOM مررز (<ConsoleMirror>) | مرر direction: ltr ہوتا ہے (تاکہ RTL ہوسٹ صفحہ اسے پلٹ نہ سکے)، اور دائیں سے بائیں متن والے spans کو unicode-bidi: bidi-override ملتا ہے۔ |
<Box title>، <Box bottomTitle> اور <Divider title> انہی مراحل سے گزرتے ہیں (drawLogicalText(buffer, x, y, text, …) کسی بھی ایک لائن کو اسی طرح ڈرا کرتا ہے)، اس لیے ان کے لیبل ترتیب میں اور جڑے ہوئے دکھائی دیتے ہیں۔
دائیں سے بائیں کریکٹرز کے بغیر متن ان سب مراحل کو چھوڑ دیتا ہے۔ مکمل بائیں سے دائیں متن کے ماڈل کی شناخت اس کے گرافیمز کی تقسیم کے دوران ہوتی ہے (ہر گرافیم پر ایک موازنہ) اور وہ غیر تبدیل شدہ راستے سے پینٹ ہوتا ہے؛ کونسول فریم بائٹ بہ بائٹ یکساں ہوتے ہیں۔
سیل کی چوڑائیاں
فراہم کردہ فونٹ اسٹیک "SF Mono", Menlo, "Cascadia Mono", Consolas, monospace ہے۔ ان میں سے کسی فونٹ میں عبرانی یا عربی گلف نہیں ہیں، اس لیے براؤزر ہر کریکٹر کے لیے متبادل فونٹ لیتے ہیں۔ macOS پر یہ Courier New ہے، جو 0.6 em پر مونو اسپیسڈ ہے: 12 px پر ہر گلف کی چوڑائی 7.2012 px ہے، جبکہ Menlo کی 7.2246 px ہے۔ یہ 0.3% کم چوڑا ہے، جو عبرانی کی پوری قطار کو تقریباً آدھے سیل تک سرکانے کے لیے کافی ہے۔
CssConsoleDriver کونسول فونٹ والے کینوس سے ہر دائیں سے بائیں span کی پیمائش کرتا ہے (وہی Blink شیپنگ اور متبادل فونٹ جو DevTools استعمال کرتا ہے)، پھر اس میں LayoutUnit (1/64 px) کے عین فرق کے برابر پیڈنگ شامل کرتا ہے۔ یوں span اتنا ہی چوڑا ہوتا ہے جتنے گرڈ سیلز کو وہ گھیرتا ہے (ایموجی جیسا چوڑا گرافیم دو شمار ہوتا ہے)۔ span کو زیادہ سے زیادہ آدھے سیل تک اندر کھینچا جاتا ہے، اس لیے متناسب متبادل فونٹ (Windows پر Cascadia Mono کے ساتھ Times New Roman) اوورفلو کرتا ہے اور اگلے span کو اپنے گلفس پر چڑھنے نہیں دیتا۔ حقیقی DevTools فرنٹ اینڈ (Chromium 151) میں عبرانی، عربی، مخلوط اور عبرانی میں ایموجی والی لائنوں اور RTL باکس عنوانات کے 64×21 فریم پر پیمائش (bun bench/devtools/bidi-shot.ts):
| فریم | قطاروں میں دائیں کنارے کا سرکاؤ |
|---|---|
| ترتیب مقرر کیے بغیر لاگ کردہ سیلز | 14.5 px (DevTools ترتیب اور شکلیں دوبارہ بدلتا ہے) |
| ترتیب مقرر، چوڑائی کی فٹنگ کے بغیر | 2.22 px |
| فراہم کردہ ڈرائیور | 0.156 px |
کنٹرول: وہی سیلز، ہر RTL گلف کی جگہ x | 1.67 px |
فراہم کردہ فریم ایموجی والی قطار کے سوا ہر قطار میں مکمل لاطینی کنٹرول سے مطابقت رکھتا ہے، اور ایموجی والی قطار میں بہتر ہے: ایموجی اپنے آس پاس کے دائیں سے بائیں span کے ساتھ فٹ ہوتے ہیں (0.03 px)، جبکہ کنٹرول کی بائیں سے دائیں ایموجی قطار فٹ نہیں ہوتی (1.66 px)۔
DevTools ہر %c span کو contain: paint کے ساتھ پینٹ کرتا ہے اور ہر ایک کو الگ سے ڈیوائس پکسلز پر بٹھاتا ہے، اس لیے جہاں دو بیک گراؤنڈ کسری مقام پر ملتے ہیں وہاں درمیان کا پکسل کسی کا بھی حصہ نہ بننے سے 1 px کی باریک لکیر چھوڑ سکتا ہے۔ Chrome اور Edge میں بیک گراؤنڈ والا span اسے دائیں جانب کے غیر شفاف پڑوسی کے نیچے 1 px تک پھیلاتا ہے، اور فٹ شدہ span اس پکسل کو اپنی پیڈنگ میں شامل کرتا ہے۔ اوپر کے چار فریموں میں سے کسی میں باریک لکیر نہیں دکھائی دیتی۔
فٹنگ بند کرنے کے لیے measureText: false پاس کریں، یا اپنا (text, bold, italic) => px پیمائش فنکشن فراہم کریں۔
ان پٹ اور ایڈیٹنگ
<Input> اور <Textarea> منطقی کرسر رکھتے ہیں۔ تیر والی کلیدیں متن میں اسٹوریج کی ترتیب سے چلتی ہیں، اس لیے دائیں سے بائیں متن میں ← بظاہر دائیں حرکت کرتا ہے۔ بلاک کرسر اسی منطقی کریکٹر پر رہتا ہے جسے وہ ڈھانپتا ہے، چاہے ترتیب بدلنے سے وہ کہیں بھی پہنچے۔ دائیں سے بائیں رن میں یہ پچھلے کریکٹر کے بائیں جانب والا سیل ہوتا ہے۔ سلیکشن بھی منطقی رینج ہے، اس لیے اس کی ہائی لائٹ مخلوط سمت والی لائنوں میں غیر متصل سیلز کو ڈھانپ سکتی ہے۔ ایک لائن والے <Input> کا افقی اسکرول منطقی کالم کی پیروی کرتا ہے، اس لیے دائیں سے بائیں طویل ویلیو کرسر کو اسکرول کر کے نظروں سے باہر لے جا سکتی ہے۔ اسپیس پر یا متن کے آخر میں کرسر الگ نان بریک اسپیس کے طور پر ڈرا ہوتا ہے، اس لیے وہ نیوٹرل رہتا ہے اور کسی بھی طرف کے نمبروں سے کبھی نہیں جڑتا۔
حدود
- پیراگراف جداکار۔ لائنیں
\nپر تقسیم ہوتی ہیں۔ U+2029 اور دوسرے پیراگراف جداکار bidi پیراگراف ختم کرتے ہیں مگر نئی لائن شروع نہیں کرتے۔ - ٹیب۔ bidi چلنے سے پہلے ٹیب اسپیسز میں بدل جاتے ہیں، اس لیے وہ سیگمنٹ جداکار (S) کے بجائے وائٹ اسپیس (WS) کا کام کرتے ہیں۔
- شیپنگ۔ صرف پریزنٹیشن فارم والے حروف کی شکلیں بنتی ہیں: عربی، فارسی، اردو اور U+FB50–U+FDFF اور U+FE70–U+FEFF کے دوسرے حروف۔ لام الف دو سیلز میں دو جڑے ہوئے حروف ہی رہتا ہے، ایک گلف والا لیگیچر نہیں بنتا۔ سریانی، N'Ko اور دوسرے جڑنے والے رسم الخط اپنی بنیادی شکلیں رکھتے ہیں۔
- کاپی کرنا۔ کونسول سے کاپی کردہ متن ڈسپلے کی ترتیب میں ہوتا ہے (
LRO/PDFنشانات کے ساتھ)، منطقی ترتیب میں نہیں۔ - ٹرمینلز۔ وہ ٹرمینلز جو BDSM اور
LROدونوں کو نظر انداز کرتے ہیں اور اپنا bidi چلاتے ہیں (مثلاً iTerm2 میں bidi فعال ہونے پر)، دائیں سے بائیں قطاروں کی ترتیب دوبارہ بدل سکتے ہیں۔ - DOM مررز۔
<ConsoleMirror>چوڑائیاں فٹ نہیں کرتا، اس لیے وہاں دائیں سے بائیں رنز اپنی چوڑائی کے 0.3% تک سرک سکتے ہیں۔
فوکس پیڈ کا ترجمہ
@textjs/react/dom کا <FocusPad> (جسے <TextCanvas> بھی رینڈر کرتا ہے) وزیٹرز کو کونسول کھولنے، صفحے پر کلک کرنے اور کلید دبانے کو کہتا ہے۔ اس کا متن ڈیفالٹ طور پر انگریزی ہے۔ اس کا ترجمہ کرنے کے لیے جن اسٹرنگز کو بدلنا چاہتے ہیں ان کے ساتھ messages پاس کریں۔ جو کیز آپ چھوڑ دیں ان کا انگریزی متن برقرار رہتا ہے، جو defaultFocusPadMessages میں درج ہے۔
import { FocusPad, type FocusPadMessages } from "@textjs/react/dom";const ja: Partial<FocusPadMessages> = { openConsole: "コンソールを開く", step: (n, total) => `${total}ステップ中${n}ステップ目`, then: (action) => `次にここをクリックして、${action}。`, shortcutOpens: (shortcut) => <>{shortcut}でコンソールが開きます。</>,};<FocusPad root={root} hints={[{ keys: "↑ ↓", label: "件数" }]} action="↑ ↓を押します" messages={ja} />;ویلیو رکھنے والی اسٹرنگ ایک فنکشن ہے جو پورا جملہ واپس کرتا ہے، اس لیے ترجمہ ویلیو کو اس میں کہیں بھی رکھ سکتا ہے۔ step، pressShortcut، then، defaultAction اور shortcutOpens فنکشن ہیں۔ step کو مرحلے کا نمبر اور مراحل کی تعداد ملتی ہے۔ then کو action prop ملتا ہے، یا action نہ ہونے پر defaultAction کا متن ملتا ہے۔ defaultAction کو پہلے ہنٹ کی کلیدیں، یا ہنٹس نہ ہونے پر null ملتا ہے۔ pressShortcut کو اسکرین ریڈرز کے لیے شارٹ کٹ کی کلیدیں ملتی ہیں، اور shortcutOpens کو شارٹ کٹ <kbd> ایلیمنٹس کی صورت میں ملتا ہے۔
messages میں وہ لیبل بھی شامل ہیں جو اسکرین ریڈرز پڑھتے ہیں، اور کونسول سائز کنٹرول (sizeControl) بھی شامل ہے۔ <TextCanvas> وہی messages prop لیتا ہے۔ <ViewportControl> بھی اسے لیتا ہے اور سائز کنٹرول کی کیز استعمال کرتا ہے۔ ⌘⌥J، Ctrl+Shift+J اور Enter جیسے کی کیپس کا ترجمہ نہیں ہوتا۔
API
import { reorderLine, paragraphDirection, resolveLevels, bidiClass, shapeArabicCodePoints } from "@textjs/core";reorderLine("שלום (abc) 123!"); // "!123 (abc) םולש": one line in display orderreorderLine("مرحبا", "auto", { shape: true }); // presentation forms, display orderparagraphDirection("123 שלום"); // "rtl" (rules P2–P3)resolveLevels(types, codePoints, direction)، applyLineRules اور reorderIndices خود الگورتھم تک رسائی دیتے ہیں: قواعد P1–I2، L1 اور L2۔