لوحة المفاتيح الكردية

مفتوح المصدر · إدخال النص الكردي · v0.4.0

لوحة المفاتيح الكردية

اكتب بالكردية في أي مكان على الويب

لوحة مفاتيح افتراضية قابلة للتضمين للسورانية (بالحرف العربي) والكرمانجية (بالحرف اللاتيني). ويدجت واحد، بـ Unicode موحّد صحيح من الأساس.

npm install kurdish-keyboard
نظام كتابة
٢
تخطيطات
٣
اعتماديات وقت التشغيل
٠
codepoint موثّق
٥٥

الكرمانجية، QWERTY + صف

تخطيط QWERTY مع صف إضافي لـ ç ê î ş û، من اليسار إلى اليمين.

السورانية

تخطيط مستمد من بيانات Unicode CLDR، من اليمين إلى اليسار.

لماذا

حرف واحد، ترميزات كثيرة

للنص الكردي على الويب عقودٌ من الترميزات المتشظية. حروف تبدو متطابقة لها رموز مختلفة: ك و ک، ي و ی، ه و ە. وهذا يكسر البحث والفرز والتدقيق الإملائي دون أن يلاحظ أحد. لا تكتب لوحة المفاتيح هذه إلا الـ codepoints الموحّدة من معيار دائرة تقنية المعلومات في حكومة إقليم كردستان (KRG)، بعد مطابقتها مع قاعدة بيانات محارف Unicode. لذلك كل نص يُكتب بها صحيح من الأساس.

عرض حي

هذا ليس screenshot. هذا هو الويدجت نفسه.

لوحات المفاتيح في هذه الصفحة ليست صورًا. إنها الـ package الحقيقي نفسه، وثيمها من خصائص CSS المخصصة. اختر تخطيطًا وابدأ الكتابة. ⇧ يُظهر الطبقة الثانية، والتخطيطات اللاتينية تضيف ⇪ Caps Lock. مفاتيح Arrow تنقلك بين المفاتيح، والـ screen-readers تستطيع استخدامه.

الميزات

كل ما يحتاجه إدخال كردي

  1. Unicode موحّد

    صحيح من الأساس.

    لا يستطيع الويدجت أن يكتب إلا الـ codepoints الموثّقة وفق معيار KRG وقاعدة UCD: دائمًا ک لا ك، ودائمًا ی لا ي، وە بوصفها حرف العلة الذي هي عليه. النص المتشظي يبقى في الماضي.

  2. نظاما كتابة، ثلاثة تخطيطات

    من اليمين إلى اليسار ومن اليسار إلى اليمين، بـ engine واحد.

    تخطيط سوراني مبني على بيانات Unicode CLDR، مع تخطيطين كرمانجيين من المجتمع. بدّل حيًا بـ setLayout()، فيتبعه الاتجاه والطبقات وCaps Lock.

  3. مصمم للجوال

    الويدجت هو لوحة المفاتيح.

    لكل حقل على حدة، يُبقي inputmode="none" لوحة مفاتيح الهاتف مخفية بينما تتولى الكتابة لوحةٌ مثبّتة أو عائمة. تكبر أهداف اللمس إلى 44px بناءً على استعلام عن قدرات الجهاز، وأبدًا دون تشمّم user-agent.

  4. دعم Rich text

    عناصر contenteditable والمحررات.

    يعمل contenteditable العادي مباشرةً دون إعداد. ومحررات الأطر مثل Lexical وProseMirror وSlate تتصل عبر محوّل إدراج صغير.

  5. مُيسَّر افتراضيًا

    أسماء منطوقة وtabindex متنقّل.

    navigation بلوحة المفاتيح وفق WAI-ARIA، وتركيز مرئي، و labels للـ screen-readers بالإنجليزية أو الكردية، قابلة للتبديل أثناء التشغيل (runtime).

  6. منسِّق النصوص القديمة

    تنظيف عقود من ك و ي.

    الدالة normalizeLegacy() تحوّل النص السوراني القديم المتشظي إلى الـ codepoints الموحّدة، بملف البيانات نفسه الذي تستخدمه لوحة المفاتيح. لا تحتاج إلى DOM، فتعمل في Node وفي أدوات سطر الأوامر أيضًا.

المبادئ

كيف بُني

  1. المعايير لا الاختراع

    الـ codepoints من معيار لوحة المفاتيح الموحّد لحكومة إقليم كردستان (KRG)، والتخطيط السوراني من Unicode CLDR. حيث يوجد معيار، لا شيء يُصنع يدويًا.

  2. البيانات لا الكود

    التخطيطات ملفات JSON تُتحقق بمخطط. الـ engine لا ينظر أبدًا إلى اسم التخطيط. التخطيط الجديد يعني بيانات جديدة، لا كودًا جديدًا.

  3. المنصة تكفي

    setRangeText للإدراج، وinputmode للهواتف، والخصائص المخصصة للتنسيق. صفر اعتماديات وقت التشغيل، ESM وCJS، وتخطيطات tree-shakable.

  4. موثّق لا مفترض

    كل codepoint رُوجع حرفًا حرفًا مقابل المصادر الأولية. وقبل كل إصدار، تُثبت مواصفةٌ قابلة للتنفيذ صحة الـ package المنشور.

الدليل

دليل التكامل

كل ما تحتاجه لإضافة لوحة المفاتيح إلى موقعك. كل مثال يعمل حيًا بجانب الكود الخاص به.

بداية سريعة

اربط، اكتب، افصل

استيراد واحد لكل تخطيط، واستدعاء واحد. تظهر اللوحة بعد الحقل. المفتاح يكتب عند موضع المؤشر، ويستبدل أي تحديد، ويُبقي التركيز في الحقل. والدالة kb.detach() تزيل اللوحة وتتراجع عن كل side effect.

import { KurdishKeyboard } from "kurdish-keyboard";
import "kurdish-keyboard/styles.css"; // optional, recommended
import { soraniLayout } from "kurdish-keyboard/layouts/sorani";

const kb = KurdishKeyboard.attachTo(document.querySelector("input"), {
  layout: soraniLayout,
});
// later: kb.detach()

حي

الخيارالنوعالافتراضيماذا يفعل
layoutLayoutلوحة بسيطةالتخطيط المعروض. استورد تخطيطًا لكل نظام كتابة، أو قدّم تخطيطك الخاص.
adapterInsertionAdapterمدمجإدراج خاص بك لمحررات الأطر. انظر «Rich text» أدناه.
suppressNativebooleanfalseيضبط inputmode="none"، فتُبقي الهواتف لوحة مفاتيحها مخفية.
position'inline' | 'docked' | 'floating''inline'مكان اللوحة. انظر «الجوال» أدناه.
labelLanguage'en' | 'ku''en'لغة labels الـ screen-reader (Shift، Space، …).

التخطيطات

ثلاثة تخطيطات، وتبديل حي

نقطة دخول واحدة لكل تخطيط، فلا يحمل موقعٌ سوراني فقط بيانات الكرمانجية في حزمته. الدالة setLayout() تبدّل حيًا: يُعاد رسم اللوحة، وينقلب الاتجاه بين اليمين إلى اليسار واليسار إلى اليمين، ويُعاد ضبط Shift وCaps Lock. التخطيطات اللاتينية تحصل على ⇪ Caps Lock، أما Shift فيعمل لمفتاح واحد في كل التخطيطات.

تخطيطك الخاص: التخطيط بيانات plain. النوع Layout مُصدَّر (export)، ويُتحقق من ملف JSON بالمخطط المنشور. المفاتيح تكتب سلاسل نصية لا محارف مفردة: Shift+و في CLDR هو وو. جدول الـ codepoints الموثّقة يأتي مع الـ package باسم kurdish-keyboard/codepoints.json. الحقول من اليمين إلى اليسار: اللوحة تضبط اتجاهها بنفسها، أما dir الخاص بالحقل فمسؤوليتك. استخدم dir="rtl" أو dir="auto" لحقول السورانية؛ ويكتب الويدجت log في الـ console إن نسيت.

import { soraniLayout } from "kurdish-keyboard/layouts/sorani";
import { kurmanjiPhonetic } from "kurdish-keyboard/layouts/kurmanji-phonetic";
import { kurmanjiOfficial } from "kurdish-keyboard/layouts/kurmanji-official";

kb.setLayout(kurmanjiPhonetic); // live swap, LTR
kb.setLayout(soraniLayout); // back to RTL

حي

Rich text

عناصر contenteditable ومحوّلك الخاص

ترتبط اللوحة بـ elements contenteditable مباشرةً دون إعداد. تمر الكتابة عبر commands التحرير الخاصة بالمتصفح نفسه، فيتصرف المؤشر والتحديد وأحداث input كما لو كانت ضغطات مفاتيح حقيقية. قاعدة واحدة: المفاتيح تعمل فقط ما دام التحديد داخل الـ element المرتبط. إذا كان المؤشر في مكان آخر، فلا يفعل المفتاح شيئًا؛ ولا يكتب أبدًا في الحقل الخطأ.

محررات الأطر مثل Lexical وProseMirror وSlate تتراجع عن التعديلات الخارجية بحكم تصميمها. ولهذه المحررات، قدّم خيار adapter. الدالتان insertChar وdeleteBack مطلوبتان؛ وinsertLineBreak وinsertParagraph اختياريتان. تعرض اللوحة مفتاحًا فقط للعمليات التي يوفرها المحوّل: بلا insertParagraph، لا مفتاح ¶. المحوّلات المدمجة مُصدَّرة أيضًا (valueAdapter، contentEditableAdapter) إن أردت تغليف أحدها.

// Plain contenteditable: nothing new to learn
KurdishKeyboard.attachTo(document.querySelector("[contenteditable]"), {
  layout: soraniLayout,
});

// Lexical (e.g. Payload CMS): supply an editor-native adapter
import {
  $getSelection,
  DELETE_CHARACTER_COMMAND,
  INSERT_LINE_BREAK_COMMAND,
  INSERT_PARAGRAPH_COMMAND,
} from "lexical";

KurdishKeyboard.attachTo(editorRootElement, {
  layout: soraniLayout,
  adapter: {
    insertChar: (text) =>
      editor.update(() => $getSelection()?.insertText(text)),
    deleteBack: () => editor.dispatchCommand(DELETE_CHARACTER_COMMAND, true),
    insertLineBreak: () =>
      editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false),
    insertParagraph: () =>
      editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined),
  },
});

حي

منطقة قابلة للتحرير (السورانية)

الجوال

كن لوحة المفاتيح

الخيار suppressNative يضبط inputmode="none"، وهي الطريقة القياسية لإخبار الهاتف أن «لهذه الصفحة لوحة مفاتيحها الخاصة». الثمن هو التصحيح التلقائي في الهاتف لذلك الحقل، لذا يُفعَّل اختياريًا لكل حقل. الوضع docked يثبّت اللوحة أسفل الشاشة ويُبقي الحقل مرئيًا؛ والوضع floating يُبقيها قرب الزاوية. تكبر أهداف اللمس إلى 44px على الـ screens اللمسية.

KurdishKeyboard.attachTo(field, {
  layout: soraniLayout,
  suppressNative: true,
  position: "docked", // or "floating"
});

حي

على الحاسوب ترى اللوحة المثبّتة. وعلى الهاتف، يُبعد inputmode="none" لوحة مفاتيح الهاتف أيضًا.

الثيم

خصائص مخصصة، بلا CSS-in-JS

استورد ملف الأنماط مرة واحدة، ثم اضبط خصائص --kkb-* على اللوحة أو على أي عنصر أب. ملف الأنماط اختياري؛ فالويدجت يعمل بدونه أيضًا. لوحتا المفاتيح أدناه لا تختلفان إلا في الخصائص المخصصة.

الخصائص الداخلية --_* مشتقة. غيّر الخصائص العامة فقط.

.theme-night {
  --kkb-key-bg: #1e293b;
  --kkb-key-color: #e2e8f0;
  --kkb-key-border: #334155;
  --kkb-pressed-bg: #334155;
  --kkb-focus-color: #38bdf8;
  --kkb-surface-bg: #1e293b;
}

الافتراضي

ثيم داكن، بـ --kkb-* فقط

الخاصيةالافتراضيما تنسّقه
--kkb-gap4pxالمسافة بين المفاتيح والصفوف
--kkb-key-size2.2rem · 44px على شاشات اللمسأصغر عرض وارتفاع للمفتاح
--kkb-key-font-size1.1rem · 1.3rem على شاشات اللمسحجم نص المفتاح
--kkb-key-bgButtonFaceخلفية المفتاح
--kkb-key-colorButtonTextلون نص المفتاح
--kkb-key-borderButtonText 40%لون حدّ المفتاح
--kkb-key-radius4pxنصف قطر زوايا المفتاح
--kkb-pressed-bg#cbdceeخلفية Shift وCaps Lock عند تفعيلهما
--kkb-focus-color#1a56a0حلقة تركيز لوحة المفاتيح
--kkb-surface-bgCanvasخلفية اللوحة المثبّتة أو العائمة

إمكانية الوصول

تنقّل بلوحة المفاتيح، أسماء منطوقة

اللوحة عبارة عن role="group" ذات تسمية، من أزرار default بنمط tabindex المتنقّل وفق WAI-ARIA. وهي محطة Tab واحدة. مفاتيح الأسهم تتنقل بين المفاتيح في الاتجاه المرئي، لذا تنعكس في اللوحات من اليمين إلى اليسار. Home وEnd تقفزان داخل الصف؛ وEnter وSpace تضغطان المفتاح. المفاتيح التي لا تُرى تحصل على أسماء (Space، ZWNJ، ⇧ Shift، ⇪ Caps Lock). يبقى التركيز بعد إعادة الـ render، و:focus-visible يُظهر outline بتباين 3:1 على الأقل.

// at attach time…
KurdishKeyboard.attachTo(field, {
  layout: soraniLayout,
  labelLanguage: "ku",
});

// …or live
kb.setLabelLanguage("en");

حي

يقول مفتاح ⇧:

اضغط Tab للدخول إلى اللوحة، ثم استخدم مفاتيح الأسهم أو Arrow.

النصوص القديمة

نظّف النص القديم

الدالة normalizeLegacy() تحوّل السورانية القديمة المتشظية (الحرفان العربيان ك و ي، و ه في موضع ە) إلى الـ codepoints الموحّدة. تستخدم هذه الـ method ملف البيانات نفسه الذي تستخدمه لوحة المفاتيح. لا تحتاج إلى DOM، فتعمل في Node وفي workers وفي أدوات سطر الأوامر.

اقرأ هذا أولًا: يُفترض أن المدخل نص كردي. التحويلان ك←ک و ي←ی يُطبَّقان دائمًا، فتتغير الاقتباسات العربية الحقيقية أيضًا؛ افصل اللغات الأخرى بنفسك. أما قاعدة ه←ە فتنظر إلى الموضع فقط: ه في آخر الكلمة تتغير (وكذلك قبل ZWNJ)؛ و ه قبل حرف عربي آخر أو تطويل أو علامة تشكيل لا تتغير. حروف العلة القديمة في وسط الكلمة لا تُكتشف، ولا يوجد قاموس. النص اللاتيني لا يتغير.

import { normalizeLegacy } from "kurdish-keyboard/normalize";

normalizeLegacy("كوردي"); // → "کوردی"
normalizeLegacy("ئێمه"); // → "ئێمە"

حي

النتيجة

CDN

بلا خطوة بناء

حزمة السكربت توفّر متغيرًا global KurdishKeyboard. الدالة attachTo فيها تقبل أسماء التخطيطات ('sorani'، 'kurmanji-phonetic'، 'kurmanji-official') أو كائنات Layout؛ والاسم غير المعروف يرمي خطأً يتضمن القائمة. وفيها أيضًا قائمة layouts وnormalizeLegacy. تحمل هذه الحزمة كل التخطيطات؛ ومع أداة bundler، استخدم مداخل الوحدات (module).

<script src="https://unpkg.com/kurdish-keyboard"></script>
<script>
  KurdishKeyboard.attachTo(document.querySelector("input"), {
    layout: "sorani",
  });
</script>

الأطر

React وVue وSvelte: بلا أغلفة

كل إدراج يرسل حدث input من نوع bubbling (inputType: 'insertText') على الحقل. لذلك ترى ارتباطات الأطر التغيير كأن المستخدم كتبه بنفسه. اربط عند التركيب (mount)، وافصل عند الإزالة (unmount).

function KurdishInput() {
  const [value, setValue] = useState("");
  const ref = useRef(null);

  useEffect(() => {
    const kb = KurdishKeyboard.attachTo(ref.current, { layout: soraniLayout });
    return () => kb.detach();
  }, []);

  return (
    <input
      dir="rtl"
      ref={ref}
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}
<script setup>
const text = ref("");
const field = ref(null);
let kb;

onMounted(() => {
  kb = KurdishKeyboard.attachTo(field.value, { layout: soraniLayout });
});
onUnmounted(() => kb?.detach());
</script>

<template>
  <input dir="rtl" ref="field" v-model="text" />
</template>

<!-- Svelte: bind:value works the same way -->

الحدود

ما لا يستطيع فعله، ولماذا

هذه rules المتصفح، لا ميزات ناقصة (miss).

لا يستطيع الكتابة في إطارات iframe من مواقع أخرى
سياسة المصدر الواحد (same-origin) تمنع أي وصول إلى الصفحات المضمّنة من أصل آخر.
لا يستطيع توليد ضغطات مفاتيح حقيقية
أحداث لوحة المفاتيح التي يولّدها سكربت تحمل isTrusted: false، والمتصفحات تتجاهل أثرها. لذلك يغيّر الويدجت قيمة الحقل مباشرة بـ setRangeText(). وهذا يعمل في كل مكان، حتى في حقول كلمات المرور.
الخيار suppressNative يوقف التصحيح التلقائي
الإعداد inputmode="none" يزيل لوحة مفاتيح الهاتف كلها لذلك الحقل، ومعها التصحيح التلقائي. هكذا تعمل الآلية، لذا يُفعَّل اختياريًا لكل حقل.
محررات الأطر تحتاج إلى محوّل
المحررات Lexical وProseMirror وSlate تملك DOM الخاص بها وتتراجع عن التعديلات الخارجية. الإدراج على مستوى المتصفح لا يستطيع التحكم بها بأمان؛ والخيار adapter موجود لها. أما contenteditable العادي فيعمل مباشرةً دون إعداد.
دعم المتصفحات
المتصفحات دائمة التحديث من السنوات الثلاث الأخيرة تقريبًا، مع Safari 15.4+. خسارة صغيرة واحدة: حدّ المفتاح الافتراضي يستخدم color-mix() (Safari 16.2+). المتصفحات الأقدم تعرض المفاتيح بدونه، أو يمكنك ضبط --kkb-key-border. لا تُشحن أي polyfills.

احصل عليه

مجاني، كما ينبغي للوحة مفاتيح أن تكون

مجاني

رخصة MIT · بلا مستويات، بلا تتبّع، بلا احتجاز

npm install kurdish-keyboard

الإصدار 0.4.0 على npm، أو ثبّت من مستودع GitHub.

اعرض على GitHub

الأسئلة

أجوبة قبل أن تسأل

ما المتصفحات المدعومة؟
المتصفحات دائمة التحديث من السنوات الثلاث الأخيرة، مع Safari 15.4+. كل واجهات المتصفح التي يستخدمها الويدجت متاحة على نطاق واسع، فلا يُشحن أي polyfill.
هل يعمل مع React وVue وSvelte؟
نعم. يرسل الويدجت بعد كل إدراج حدثَ input من نوع bubbling، فترى ارتباطات الأطر التغيير دون أغلفة.
هل يكتب في أي حقل؟
أي عنصر input أو textarea أو contenteditable في الصفحة نفسها، ومحررات Rich text عبر محوّل. أما إطارات iframe من مواقع أخرى فيمنعها أمان المتصفح.
لماذا لا يكتب الكاف العربية؟
في النص الكردي، ك يشبه ک في الشكل فقط، لكنه يكسر البحث والفرز دون أن يلاحظ أحد. لذلك يكتب الويدجت ک دائمًا. أما الحروف العربية الحقيقية فموجودة على طبقة Shift في التخطيط السوراني، لكتابة الأسماء العربية.
هل أستطيع صنع تخطيطي الخاص؟
نعم. التخطيطات ملفات JSON بسيطة تُتحقق بمخطط منشور. يعرض الـ engine أي تخطيط صالح كما هو، فتخطيط الـ community إضافة لا fork.