@akhatmirzo/ui

Matn

Kirill ↔ lotin, o'zbekcha qidiruv, slugify va matnni qisqartirish.

O'zbek matni bir necha shaklda yoziladi: lotin va kirill, apostrofning to'rt-besh xil varianti (' ʻ ‘ ’), katta-kichik harflar. Bu funksiyalar shu farqlarni bir xil tushunadi. Hammasi sof funksiyalar: React'siz, bog'liqliksiz va SSR'da xavfsiz.

import {
  cyrToLat,
  latToCyr,
  normalizeUz,
  searchMatch,
  fuzzyMatch,
  splitByRanges,
  slugify,
  truncate,
  truncateMiddle,
  capitalize,
} from '@akhatmirzo/core';

Transliteratsiya

Matnni yozing yoki pastdagi namunalardan birini tanlang:

cyrToLat
G'uzor tumani
latToCyr
Ғузор тумани
normalizeUz
guzor tumani

cyrToLat

function cyrToLat(s: string, options?: TranslitOptions): string;

O'zbek kirill matnini lotin yozuviga o'giradi. Imlo qoidalari hisobga olinadi: so'z boshidagi е → ye, ц → ts, ъ → ', ь tushib qoladi. Katta harflar saqlanadi — butunlay katta so'zda Ш → SH, aks holda Sh. Kirill bo'lmagan belgilar o'zgarmaydi.

cyrToLat('Шаҳар'); // 'Shahar'
cyrToLat('ЎЗБЕКИСТОН'); // "O'ZBEKISTON"
cyrToLat('ер, поезд, маъно'); // "yer, poyezd, ma'no"
cyrToLat('центр'); // 'tsentr'
cyrToLat('Ғузор', { apostrophe: 'ʻ' }); // 'Gʻuzor'
PropTipStandartTavsif
smajburiystring—Kirill matn
options.apostrophestring"'"o', g' va ъ uchun ishlatiladigan belgi, masalan 'ʻ'

latToCyr

function latToCyr(s: string): string;

O'zbek lotin matnini kirillga o'giradi. o' va g' da apostrofning istalgan varianti qabul qilinadi. Boshqa joydagi apostrof tutuq belgisi ъ ga aylanadi, so'z boshidagi e esa э ga. s'h kabi ajratilgan juftliklar to'g'ri o'qiladi.

latToCyr("O'zbekiston"); // 'Ўзбекистон'
latToCyr('Gʻuzor'); // 'Ғузор'
latToCyr('SHAHAR'); // 'ШАҲАР'
latToCyr("ma'no"); // 'маъно'
latToCyr('ekran'); // 'экран'
latToCyr("Is'hoq"); // 'Исҳоқ'

ts → ц tiklanmaydi

Lotin yozuvida ts ham ц, ham т + с bo'lishi mumkin, shuning uchun latToCyr('tsex') → 'тсех'. Rus tilidan kirgan so'zlarda natijani tekshiring.

normalizeUz

function normalizeUz(s: string | null | undefined): string;

Qidiruv kaliti yasaydi: kichik harf, kirill → lotin, barcha apostroflar olib tashlanadi. Ikki satrni "bir xilmi" deb solishtirish yoki o'z qidiruvingizni yozish uchun. null va undefined → ''.

normalizeUz('Gʻuzor'); // 'guzor'
normalizeUz("G'uzor"); // 'guzor'
normalizeUz('Ғузор'); // 'guzor'
normalizeUz("O'zbekiston"); // 'ozbekiston'

cyrToLat bilan farqi

normalizeUz da kirill е doim e bo'ladi (so'z boshida ham): normalizeUz('Ер юзи') → 'er yuzi', cyrToLat esa 'Yer yuzi' qaytaradi. Shunda so'rov bo'lagi so'z o'rtasidagi harflarni ham topadi.

Qidiruv

searchMatch

function searchMatch(
  text: string | null | undefined,
  query: string | null | undefined,
): SearchMatchResult; // { match: boolean; ranges: TextRange[] }

Qism satr qidiruvi: registr, apostrof varianti va yozuv (kirill/lotin) farqi hisobga olinmaydi. ranges — asl matndagi barcha mosliklar ([start, end), slice bilan mos), shuning uchun kirillcha matnda lotincha so'rovni ham to'g'ri ajratib ko'rsatish mumkin. Bo'sh so'rov hamma narsaga mos keladi. Combobox qidiruvi va DataTable filtri shu funksiyada ishlaydi.

Sinab ko'ring: chir, ғуз, fargona, qo'qon

  • Shahrisabz
  • Шаҳрихон
searchMatch('Toshkent', 'тош'); // { match: true, ranges: [[0, 4]] }
searchMatch('Ғузор тумани', "g'uzor"); // { match: true, ranges: [[0, 5]] }
searchMatch("Farg'ona", 'fargona'); // { match: true, ranges: [[0, 8]] }
searchMatch('Ota-ona, ota', 'ota'); // { match: true, ranges: [[0, 3], [9, 12]] }
searchMatch('Shahrisabz', 'xiva'); // { match: false, ranges: [] }
searchMatch('Toshkent', ''); // { match: true, ranges: [] }

fuzzyMatch

function fuzzyMatch(
  text: string | null | undefined,
  query: string | null | undefined,
): FuzzyMatchResult | null; // { score: number; ranges: TextRange[] }

Noaniq qidiruv: so'rov harflari matnda shu tartibda uchrashi kerak, orasida boshqa harflar bo'lishi mumkin. So'z boshidagi va ketma-ket mosliklar yuqoriroq ball oladi. Mos kelmasa — null. Normallashtirish searchMatch bilan bir xil, so'rovdagi bo'shliqlar e'tiborga olinmaydi. CommandPalette shu bilan ishlaydi.

Harflar tartibi muhim: mq, hsb, prof

  • Yangi buyurtma23
fuzzyMatch('Yangi buyurtma', 'ybu'); // { score: 23, ranges: [[0, 1], [6, 8]] }
fuzzyMatch('Yangi buyurtma', 'ybuy'); // { score: 29, ranges: [[0, 1], [6, 9]] }
fuzzyMatch('Sozlamalar', 'xyz'); // null

score ning mutlaq qiymati ma'no bermaydi — undan faqat natijalarni o'zaro saralash uchun foydalaning: results.sort((a, b) => b.score - a.score).

splitByRanges

function splitByRanges(text: string, ranges: readonly TextRange[]): TextSegment[];
// TextSegment = { text: string; match: boolean }

Matnni searchMatch yoki fuzzyMatch qaytargan ranges bo'yicha bo'laklarga ajratadi — topilgan qismni <mark> bilan chizish uchun.

splitByRanges('Toshkent', [[0, 4]]);
// [{ text: 'Tosh', match: true }, { text: 'kent', match: false }]
highlight.tsx
import { searchMatch, splitByRanges } from '@akhatmirzo/core';

export function Highlight({ text, query }: { text: string; query: string }) {
  const { ranges } = searchMatch(text, query);
  return (
    <>
      {splitByRanges(text, ranges).map((part, i) =>
        part.match ? <mark key={i}>{part.text}</mark> : <span key={i}>{part.text}</span>,
      )}
    </>
  );
}

Matn yordamchilari

slugify: fargona-viloyati-2026

truncateMiddle
shartnoma-mchj…ngan.docx
truncate
shartnoma-mchj-akhatmir…

slugify

function slugify(s: string | null | undefined): string;

URL uchun slug: o'zbekcha matn (kirill ham) lotinga o'giriladi, apostroflar olib tashlanadi, qolgan belgilar - bilan almashtiriladi.

slugify("Farg'ona viloyati"); // 'fargona-viloyati'
slugify('Тошкент шаҳри'); // 'toshkent-shahri'
slugify('Ер юзи'); // 'yer-yuzi'
slugify("Farg'ona viloyati — 2026"); // 'fargona-viloyati-2026'

truncate

function truncate(s: string, max: number, ellipsis?: string): string;

Matnni oxiridan qisqartiradi. Natija ellipsis bilan birga max belgidan oshmaydi, oxirgi bo'shliq tashlanadi. Belgilar kod nuqtasi bo'yicha sanaladi — emoji o'rtasidan bo'linmaydi.

truncate('Salom dunyo', 7); // 'Salom…'
truncate('Salom dunyo', 8, '...'); // 'Salom...'
truncate('Salom', 10); // 'Salom'

truncateMiddle

function truncateMiddle(s: string, max: number, ellipsis?: string): string;

Matnni o'rtasidan qisqartiradi. Fayl nomida kengaytma va nomning oxiri saqlanadi — bir xil boshlanadigan fayllarni ajratish oson. FileUpload ro'yxati shundan foydalanadi.

truncateMiddle('hisobot-oktabr-2026.pdf', 22); // 'hisobot-oktab…2026.pdf'
truncateMiddle('shartnoma-mchj-akhatmirzo-imzolangan.docx', 24); // 'shartnoma-mchj…ngan.docx'
PropTipStandartTavsif
smajburiystring—Asl matn
maxmajburiynumber—Natijaning maksimal uzunligi (ellipsis bilan birga)
ellipsisstring'…'Qisqartirilgan joy belgisi

capitalize

function capitalize(s: string): string;

Birinchi harfni katta qiladi, qolganiga tegmaydi.

capitalize("o'zbekiston"); // "O'zbekiston"
capitalize('toshkent shahri'); // 'Toshkent shahri'

isApostrophe va UZ_APOSTROPHES

const UZ_APOSTROPHES: string; // "ʻʼ‘’`´'"
function isApostrophe(ch: string | undefined): boolean;

O'zbek yozuvida apostrof o'rnida uchraydigan barcha belgilar va ularni tekshirish funksiyasi.

isApostrophe('ʻ'); // true
isApostrophe('a'); // false

Tiplar

type TextRange = [start: number, end: number]; // asl matndagi UTF-16 indekslar
interface TextSegment {
  text: string;
  match: boolean;
}
interface SearchMatchResult {
  match: boolean;
  ranges: TextRange[];
}
interface FuzzyMatchResult {
  score: number;
  ranges: TextRange[];
}
interface TranslitOptions {
  apostrophe?: string;
}

Sahifada