본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 21. 20:23

네이티브 우르두어 RTL 지원을 갖춘 AI 도서 작가 구축기 (그리고 비영어권 AI에 대해 배운 점)

요약

비영어권 사용자를 위해 RTL(우측에서 좌측으로 읽기) 지원과 Nastaliq 폰트 렌더링을 최적화한 AI 도서 집필 플랫폼 KitaabAI 구축 사례를 다룹니다. 폰트 번들링, CSS 속성 활용, LLM 생성 품질 개선 등 기술적 해결책을 제시합니다.

핵심 포인트

  • 우르두어 특유의 Nastaliq 미학을 위해 폰트 번들링 필수
  • RTL 환경에서 줄 간격(line-height) 및 unicode-range 최적화 필요
  • 비영어권 시장을 위한 AI 제품 구축 시 렌더링과 생성 품질의 중요성

모든 "AI 혁명" 관련 기사들은 당신이 영어로 글을 쓴다고 가정합니다.

5억 명의 우르두어 사용자가 있습니다. 작년까지만 해도, 그들 중 단 한 명도 Sudowrite, NovelAI, 또는 Jasper를 열어 자신의 언어로 소설을 쓸 수 없었습니다. 단순히 품질이 낮은 수준이 아니었습니다. 도구들이 우르두어를 박스(깨진 글자)로 렌더링하거나, 문단 중간에 우측에서 좌측으로 흐르는 RTL (Right-to-Left) 흐름을 망가뜨리거나, 200단어 이상은 생성을 거부했습니다.

저는 우르두어를 번역을 위한 부차적인 요소가 아닌, 일급 시민(first-class citizen)으로 취급하는 AI 도서 집필 플랫폼인 KitaabAI를 구축하는 데 8개월을 보냈습니다. 이것은 비영어권 시장을 위한 AI 제품을 구축하는 것에 대해 제가 배운 점과, 이를 가능하게 만든 구체적인 기술적 결정들에 대한 이야기입니다.

스크린샷 하나로 보는 문제점

주요 AI 글쓰기 도구를 하나 열어보세요. 다음을 붙여넣어 보세요:

یہ ایک کہانی ہے جو رات کے اندھیرے میں شروع ہوتی ہے۔

세 가지 문제가 발생합니다:

  1. 폰트 렌더링 (Font rendering) — 대부분의 도구는 Nastaliq 미학을 파괴하는 기본 아랍어 폰트로 대체됩니다 (우르두어는 Naskh가 아닌 Nastaliq로 작성됩니다).
  2. RTL 흐름 (RTL flow) — 문장 부호가 잘못된 쪽으로 이동하며, 영어와 우르두어가 섞인 줄의 순서가 뒤바뀝니다.
  3. 생성 품질 (Generation quality) — LLM (Large Language Model)이 영어로 응답하거나, 힌디-우르두어 음차(transliteration)로 전환하거나, 2문장만 생성하고 멈춰버립니다.

50,000단어 분량의 소설을 쓰는 데 있어, 이 중 하나라도 발생하면 치명적입니다.

아키텍처 결정 1: 시스템 폰트가 아닌 Mehr Nastaliq

첫 번째 본능은 "OS가 폰트를 선택하게 하자"입니다. 그러지 마세요.

우르두어는 아랍어 Naskh와는 완전히 달라 보이는 특유의 미학인 Nastaliq 스크립트를 가지고 있습니다. Windows의 Microsoft 기본 우르두어 폰트는 수용할 만합니다. Apple은 괜찮습니다. Android는 끔찍합니다. Linux의 브라우저는 글자가 문자 박스로 나타납니다.

해결책: 폰트를 번들(bundle)로 포함하세요.

// src/index.css
@font-face {
  font-family: 'Mehr Nastaliq Web';
...

여기서 두 가지가 중요합니다:

  • unicode-range를 사용하여 우르두어 문자가 나타날 때만 폰트를 다운로드하도록 설정합니다 (영어 전용 사용자에게 약 400KB를 절약해 줍니다).
  • line-height: 2.2 — Nastaliq 문자는 수직 하단부(descenders)가 매우 길게 뻗어 나갑니다. 기본값인 1.5를 사용하면 줄 간격이 겹치게 됩니다.

아키텍처 결정 2: 논리적 CSS 속성 (Logical CSS properties)

모든 RTL(Right-to-Left) 앱에서 가장 까다로운 버그는 **혼합 방향 상태 (mixed-direction state)**입니다. 사용자가 언어를 전환했을 때 UI의 절반은 반전되고, 나머지 절반은 그렇지 않은 현상입니다.

해결책은 매우 단순합니다. 다시는 margin-lefttext-align: left를 작성하지 않는 것입니다.

- className="ml-4 pl-2 text-left border-l-2"
+ className="ms-4 ps-2 text-start border-s-2"

Tailwind는 ms-, me-, ps-, pe-, text-start, text-end, border-s, border-e를 제공합니다. 모든 방향성 유틸리티에는 그에 상응하는 논리적(logical) 대응물이 있습니다. 문서 루트에 dir="rtl"을 설정하면 쉐브론(chevrons), 드롭다운, 진행 표시줄(progress bars)을 포함한 전체 UI가 자동으로 반전됩니다.

제가 현재 ESLint 플러그인을 통해 강제하고 있는 규칙은 다음과 같습니다: 코드베이스 어디에도 물리적 방향(physical direction) 유틸리티를 사용하지 말 것.

아키텍처 결정 3: 언어 인지 프롬프트 (번역이 아닌 방식)

"우르두어 지원"에 대한 순진한 접근 방식은 다음과 같습니다:

  1. 영어 프롬프트를 가져옵니다.
  2. GPT-4를 사용하여 우르두어로 번역합니다.
  3. 생성합니다.
  4. 기도합니다.

이 방식은 문법적으로는 우르두어이지만, 스타일 면에서는 힌두스탄어(Hindi-Urdu) 구어체에 가깝게 출력됩니다. 실제 우르두어 문학은 번역 기반의 프롬프트로는 결코 도달할 수 없는 특정 격식(register) — 즉, 페르시아의 영향을 받은 격식 있고 풍부한 어휘를 가지고 있습니다.

해결책: 실제 우르두어 작가가 작성한 언어 네이티브 시스템 프롬프트(language-native system prompts)를 사용하는 것입니다.

const SYSTEM_PROMPTS = {
  en: `You are a professional novelist. Write in clean, modern English prose...`,
  ur: `آپ ایک تجربہ کار اردو ادیب ہیں۔ آپ کا اسلوب کلاسیکی اردو ادب جیسا ہے — `
... 

참조 작가들(ابن صفی, انتظار حسین, قراۃ العین حیدر)은 모델의 스타일을 실제 우르두어 문학에 고정시킵니다. 그 차이는 측정 가능합니다. 베타 리더들은 번역 방식의 경우 2.8/5점을 준 반면, 언어 네이티브 프롬프트에는 일관되게 4.2/5점을 부여했습니다.

아키텍처 결정 4: 전체 도서가 아닌 12k 토큰 청크 단위 작업

모든 "AI 도서 작가 (AI book writer)" 데모는 2,000단어를 생성하고 멈춥니다. 그러면 사용자가 다시 2,000단어를 붙여넣고 프롬프트를 입력해야 합니다. 6장(Chapter 6)쯤 되면, AI는 주인공의 이름조차 잊어버립니다.

해결책은 3계층 메모리 시스템입니다:

interface ChapterContext {
  bookBible: string;       // 500 토큰 — 절대 변하지 않음
  outlineSummary: string;  // 800 토큰 — 모든 장(chapter)의 요약
...

도서 바이블(book bible)은 도서 생성 시점에 한 번 생성됩니다 (캐릭터, 세계관 규칙, 문체 노트 등). 개요 요약(outline summary)은 각 장이 완료됨에 따라 업데이트됩니다. 마지막 2개 장은 문체(prose voice)의 일관성을 유지하기 위해 원문 그대로(verbatim) 전달됩니다.

토큰 예산: 12,000 입력 → 4,000–6,000 출력 (≈ 한 장 전체). 이는 스트리밍 복잡성 없이 단일 Edge Function 호출 내에 들어가는 규모입니다.

아키텍처 결정 5: RTL PDF 렌더링은 그 자체로 지옥의 한 종류입니다

생성은 쉬운 부분이었습니다. Amazon KDP를 위한 PDF 내보내기(Exporting)는 프로젝트를 거의 무산시킬 뻔했습니다.

문제는 모든 JavaScript PDF 라이브러리(jsPDF, pdfmake, react-pdf)가 텍스트를 왼쪽에서 오른쪽으로 흐르는 글리프(glyph) 시퀀스로 취급한다는 점입니다. 여기에 우르두어(Urdu)를 넣으면 다음 세 가지 실패 모드 중 하나가 발생합니다:

  • 글자들이 결합되지 않고 개별 형태로 렌더링됨.
  • 단어 중간에서 줄 바꿈이 일어남.
  • 문장 부호가 잘못된 쪽으로 밀려남.

마침내 작동한 해결책은 문단별로 스크립트를 감지하여 서로 다른 렌더러(renderer)로 라우팅하는 하이브리드 엔진이었습니다.

function isRtlText(text: string): boolean {
  const rtlChars = /[؀-ۿݐ-ݿﭐ-﷿ﹰ-]/;
  const rtlCount = (text.match(rtlChars) || []).length;
...

네, RTL 문단은 래스터화된 캔버스 블록(rasterized canvas blocks)이 됩니다. 이로 인해 텍스트 선택(text-selection) 기능은 상실됩니다. 하지만 Kindle, Apple Books, 그리고 KDP 종이책(paperback)에서 올바르게 렌더링됩니다 — 이것이 유일하게 중요한 지표였습니다.

JavaScript에서 순수 벡터(pure-vector) 방식의 RTL PDF를 구현하는 것은 2026년에도 여전히 미해결 과제로 남아 있습니다. 만약 이를 해결하신다면, 제게 이메일을 보내주세요.

내가 틀렸던 점 (그리고 바꾸고 싶은 점)

  1. 모든 곳에 margin-left를 사용하며 시작했습니다. 이틀 동안 이를 ms-로 대량 교체하는 데 시간을 허비했습니다. 첫날부터 논리적 속성 (Logical properties)을 사용하세요.

  2. 언어 감지를 GPT-4에 의존했습니다. GPT-4는 우르두어 문장 속에서 영어 단어를 포착하고 응답 중간에 언어를 전환해 버렸습니다. 이제 저는 모든 생성 호출 전에 결정론적 문자 비율 감지기 (Deterministic character-ratio detector, 위에서 언급한 것)를 사용합니다.

  3. 폰트 라이선스를 과소평가했습니다. Mehr Nastaliq는 웹 사용이 무료입니다. 하지만 많은 아름다운 Nastaliq 폰트들은 그렇지 않습니다. 번들링하기 전에 최종 사용자 라이선스 계약 (EULA)을 읽으세요.

  4. 영어 UI를 먼저 구축한 뒤 우르두어를 사후 적용했습니다. 올바른 순서는 첫 번째 줄부터 dir (방향성)에 구애받지 않도록 구축하는 것입니다. 사후 적용하는 데 3주의 시간이 소요되었습니다.

이것이 열어준 것들

KitaabAI는 이제 네이티브 우르두어 지원을 갖춘 유일한 AI 도서 작가입니다. "모든 주요 AI 도구가 무시했던" 시장은 실제로 존재했습니다:

  • 첫 달 가입자의 60%가 파키스탄, 인도, 영국 및 걸프 지역에서 유입되었습니다.
  • 평균 우르두어 사용자는 월 30,000단어 이상을 생성하며, 이는 영어 사용자보다 높은 참여도를 보입니다.
  • 경쟁자가 없습니다. Sudowrite, NovelAI, Jasper는 여전히 우르두어를 지원하지 않습니다.

교훈은 "우르두어가 특별하다"는 것이 아닙니다. 교훈은 AI 툴링 붐에는 수백 개의 이러한 공백이 존재한다는 것입니다 — 벵골어 (2억 7천만 명의 화자), 인도네시아어 (2억 7천만 명), 베트남어 (9천 5백만 명), 타밀어 (7천 5백만 명). 언어를 단순한 현지화 체크박스가 아닌 일급 시민 (First-class citizen)으로 대우하는 사람에게는 각각이 Sudowrite 규모의 기회입니다.

만약 AI 도구를 구축하고 있다면, 다음 10억 명의 사용자는 영어를 사용하지 않습니다. 그에 맞춰 구축하세요.

기술 스택 레퍼런스

궁금해하실 분들을 위해:

  • 프론트엔드 (Frontend): React 18 + Vite 5 + Tailwind CSS (논리적 속성만 사용)
  • 상태 관리 (State): Zustand + TanStack Query
  • 인증 + DB (Auth + DB): Supabase (RLS가 적용된 Postgres)
  • AI: OpenAI GPT-4o + Anthropic Claude 3.5 (장애 조치용/Failover)
  • 엣지 함수 (Edge functions): Supabase 위의 Deno
  • PDF 내보내기 (PDF export): 커스텀 하이브리드 jsPDF + html2canvas 엔진
  • 폰트 (Fonts): Mehr Nastaliq Web (우르두어), Inter (영어 UI)

kitaabai.com에서 무료로 체험해 보세요 — 우르두어와 영어 모두 지원하며, 신용카드는 필요하지 않습니다.

질문이나 반론이 있으신가요? 댓글을 남겨주세요. 특히 JS에서 벡터 RTL PDF 렌더링 문제를 해결해 보신 분이 있다면 — 제가 커피 한 잔 대접하겠습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0