arabicfmt-mcp について
arabicfmt-mcpは、JavaScriptとTypeScript向けのアラビア語フォーマットライブラリです。アラブ連盟22か国の通貨、数値、日付、RTLテキストを扱います。入力にはMCP機能の説明がありません。
主な機能
- 01アラビア通貨と桁数の整形
- 02ヒジュラ暦の日付整形
- 03数値のアラビア語表記変換
- 04小切手金額の文字表記
- 05RTLと双方向テキストの処理
活用シーン
- 01アラビア語の請求金額を生成
- 02地域に応じたヒジュラ暦表示
- 03東アラビア数字の解析
- 04混在テキストの方向問題を修正
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
17掲載時のツール一覧 · 3 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| amount | number | はい | 整形する金額。 |
| locale | string | いいえ | BCP-47 ロケール(例:'ar'、'ar-SA'、'en')。デフォルトは 'ar'。 |
| currency | string | いいえ | ISO 4217 通貨コード(例:'SAR'、'AED'、'KWD')。デフォルトは SAR 圏の既定値。 |
| numerals | enum | いいえ | 数字体系:'latn'(1234)、'arab'(東アラビア数字 ١٢٣٤)、または 'arabext'(ペルシア語/ウルドゥー語の数字 ۱۲۳۴)。latn | arab | arabext |
詳細
arabicfmt
JavaScript と TypeScript 向けのアラビア語優先フォーマット
通貨記号 · ヒジュラ暦/イスラム暦 · 数値の単語表記 · تفقيط · 6 種類の複数形 · RTL/双方向テキスト —
アラブ連盟の全 22 か国に対応し、依存関係はゼロ、TypeScript の型定義も完備しています。
أرقامٌ وعملاتٌ وتواريخُ هجريةٌ ولغةٌ عربيةٌ سليمة — في سطرٍ واحد.
arabicfmt は、通貨記号、数値の精度、ヒジュラ暦/イスラム暦の日付、RTL の双方向テキスト、アラビア語の数値の単語表記、 تفقيط など、アラビア語のフォーマットに必要な機能一式を、依存関係ゼロの単一パッケージで扱える唯一の JavaScript ライブラリです。TypeScript の型定義も完備しています。Node、ブラウザー、Deno、Bun、React Native で動作します。
0.1.5 の新機能: Unicode 17.0/18.0 への移行で追加されたすべての通貨記号(SAR
U+20C1、MVRU+20C2、AEDU+20C3、OMRU+20C4)に対応しました。さらに、実際に表示するための機能として、型付きパーツ、生成される@font-face、価格範囲、日付対応の移行レジストリを追加しました。
npm install arabicfmt
他のライブラリで見られる問題
| 問題 | 他のライブラリ | arabicfmt |
|---|---|---|
| サウジアラビア・リヤル U+20C1 | ﷼(イランのリヤル、U+FDFC)を出力 | 安全なテキストフォールバック付きで正しい U+20C1 を使用 |
| Unicode 18.0 の通貨記号(MVR/AED/OMR) | 未エンコード、または古い略称のまま | 4 種類すべての記号に加え、transitionStatus() と生成済みの @font-face |
| 新しい記号のスタイル設定 | 書式設定済み文字列から記号を正規表現で取り出す | formatCurrencyToParts() — 記号は独立した型付きパーツです |
| イラク・ディナール(IQD)の小数桁数 | 0(CLDR の実用上の値) | 3 桁 — ISO 4217 の法的基準 |
| ヒジュラ暦の日付出力 | Node、Chrome、Safari、Hermes で異なる | 固定されたウンム・アル=クラーのテーブル — すべてのエンジンで同一 |
| アラビア語の複数形 | 1~2 形式。アラビア語では法的に 6 形式が必要 | CLDR の 6 形式システムを完全サポート(zero/one/two/few/many/other) |
| 数字をアラビア語の単語に変換 | 依存関係ゼロで使える方法がない | arabicToWords(1234) → 「ألف ومئتان وأربعة وثلاثون」 |
| 小切手用の金額表記(تفقيط) | 自分で実装すると文法を間違えやすい | spellCurrency(1234.5, {currency:"SAR"}) → 「ألف ومئتان وأربعة وثلاثون ريالاً وخمسون هللةً」 |
| 序数(ترتيبية) | 非対応、または性別を考慮しない | arabicOrdinal(25) → 「الخامس والعشرون」。性別に対応 |
| 時間の口語表現 | Intl.DurationFormat のサポートはごく限定的 | formatDuration(7_500_000) → 「ساعتان وخمس دقائق」。一致規則に完全対応 |
| RTL 文中の表示崩れ | 電話番号が文の途中で反転 | Unicode アイソレートで LTR の文字列を自動的に囲みます |
| 東アラビア数字の解析 | parseInt("١٢٣") → NaN | parseNumber("١٬٢٣٤٫٥٦") → 1234.56 |
| アラビア語の URL スラッグ | 空文字列になる、または文字化けする | slugify("مدينة جدة") → "mdynh-jdh" |
| IBAN/サウジアラビア ID の検証 | 不正な番号も受け入れる正規表現 | 実際の ISO 7064 mod-97 と Luhn のチェックサム |
インストール
npm install arabicfmt
# or
yarn add arabicfmt
# or
pnpm add arabicfmt
要件: Node.js ≥ 18 · TypeScript ≥ 4.7(任意) · 実行時依存関係ゼロ。
ブラウザー/CDN — ビルド不要
すべてのリリースは、jsDelivr と unpkg の CDN に自動でミラーリングされます。ブラウザー向けの ESM バンドルを URL から直接インポートできるため、インストールやバンドラーは不要です。
<script type="module">
import { formatCurrency, formatHijri } from "https://cdn.jsdelivr.net/npm/arabicfmt/+esm";
console.log(formatCurrency(1234.5, { currency: "SAR", numerals: "arab" })); // ١٬٢٣٤٫٥٠ ر.س
console.log(formatHijri(new Date(), { numerals: "arab" })); // ٢٧ ذو الحجة ١٤٤٧ هـ
</script>
サブパスも使用できます。たとえば、通貨モジュールだけを使う場合は https://cdn.jsdelivr.net/npm/arabicfmt/dist/currency/index.js を指定します。本番環境では、たとえば [email protected] のようにバージョンを固定してください。
クイックスタート
import {
formatCurrency, // correct symbol + precision for every Arab currency
formatCurrencyRange, // "1,000.00 – 5,000.00 ر.س"
formatCurrencyToParts, // typed parts — font-scope just the new Unicode sign
transitionStatus, // "none" | "announced" | "encoded" for any date
signFontFaceCSS, // the scoped @font-face the new signs need
formatCompact, // 1,200,000 → "1.2M" / "١٫٢ مليون"
arabicToWords, // 1234 → "ألف ومئتان وأربعة وثلاثون"
spellCurrency, // تفقيط: 1234.5 SAR → "...ريالاً وخمسون هللةً"
arabicOrdinal, // 25 → "الخامس والعشرون"
formatDuration, // 7_500_000ms → "ساعتان وخمس دقائق"
formatFileSize, // 1536 → "1.5 كيلوبايت"
formatRelativeTime, // "منذ ٣ أيام"
formatList, // ["أحمد","علي"] → "أحمد وعلي"
parseCurrency, // "١٬٢٣٤٫٥٠ ر.س" → 1234.5
arabicPlural, // full 6-form Arabic plural selection
sortArabic, // Arabic-locale collation
slugify, // "مدينة جدة" → "mdynh-jdh" (URL slugs)
isValidIBAN, // ISO 7064 mod-97 IBAN checksum
isValidSaudiId, // Saudi national ID / Iqama check digit
isolateForeign, // fix broken RTL sentences
normalizeForSearch, // search-key normalization
detectLocale, // auto-detect from browser / Node environment
} from "arabicfmt";
import { formatHijri, toHijri } from "arabicfmt/umalqura"; // deterministic Hijri calendar
// Currency
formatCurrency(1.2, { currency: "KWD" }); // "1.200 د.ك"
formatCurrency(1234, { locale: "ar-SA", numerals: "arab" }); // "١٬٢٣٤٫٠٠ ر.س"
formatCurrency(-500, { currency: "SAR", accounting: true }); // "(500.00 ر.س)"
formatCurrencyRange(1000, 5000, { currency: "SAR" }); // "1,000.00 – 5,000.00 ر.س"
formatCompact(1_500_000, { locale: "ar", numerals: "arab" }); // "١٫٥ مليون"
// The Unicode currency-sign transition, as data
transitionStatus("AED"); // "encoded" (Unicode 18.0)
transitionStatus("AED", new Date("2026-01-01")); // "announced"
transitionStatus("KWD"); // "none" — Kuwait has no sign
signFontFaceCSS({ src: "/fonts/signs.woff2" }); // @font-face … unicode-range: U+20C1…U+20C4
// Number to Arabic words
arabicToWords(1234); // "ألف ومئتان وأربعة وثلاثون"
arabicToWords(1_000_000); // "مليون"
arabicToWords(5, { gender: "female" }); // "خمس"
// Spell money for invoices & cheques (التفقيط)
spellCurrency(1234.5, { currency: "SAR" });
// "ألف ومئتان وأربعة وثلاثون ريالاً وخمسون هللةً"
spellCurrency(100, { currency: "SAR", suffix: true }); // "مئة ريال فقط لا غير"
// Ordinals — gender-aware
arabicOrdinal(1); // "الأول"
arabicOrdinal(25); // "الخامس والعشرون"
arabicOrdinal(1, { gender: "female" }); // "الأولى"
// Duration & file size
formatDuration(7_500_000); // "ساعتان وخمس دقائق"
formatFileSize(1536); // "1.5 كيلوبايت"
// Lists
formatList(["أحمد", "محمد", "علي"]); // "أحمد ومحمد وعلي"
formatList(["تفاح", "موز"], { type: "disjunction" }); // "تفاح أو موز"
// Hijri dates (deterministic — same output on Node, Chrome, Safari, Hermes)
formatHijri(new Date("2025-09-23")); // "1 ربيع الآخر 1447 هـ"
formatHijri(new Date("2025-09-23"), { numerals: "arab" }); // "١ ربيع الآخر ١٤٤٧ هـ"
toHijri(new Date("2025-09-23")); // { year: 1447, month: 4, day: 1 }
// Relative time
formatRelativeTime(new Date(Date.now() - 3 * 86400_000)); // "منذ 3 أيام"
// Parse formatted strings back to numbers
parseCurrency("١٬٢٣٤٫٥٠ ر.س"); // 1234.5
parseCurrency("(500.00 SAR)"); // -500
// RTL
isolateForeign("اتصل على +1 (555) 234-5678 الآن"); // phone stays intact in RTL
// Locale auto-detection
detectLocale(); // "ar-SA" in a Saudi browser, "ar-EG" in Node with LANG=ar_EG
通貨の書式設定
記号の方式:symbolMode
サウジアラビア・リヤルには、2025 年 9 月に独自の Unicode 記号(U+20C1)が割り当てられました。ほとんどのライブラリは、誤った合字(イラン・リヤルの U+FDFC)を出力するか、SAR にフォールバックします。arabicfmt なら、自由に制御できます。
import { formatCurrency, resolveCurrencySymbol, getCurrencyInfo } from "arabicfmt/currency";
formatCurrency(1234.5, { currency: "SAR" });
// → "1,234.50 ر.س" (auto: safe text symbol, renders everywhere today)
formatCurrency(1234.5, { currency: "SAR", symbolMode: "new" });
// → "1,234.50 " (U+20C1 — use with a webfont; see webfont guide below)
formatCurrency(1234.5, { currency: "SAR", symbolMode: "code" });
// → "1,234.50 SAR" (ISO code — for accounting tables)
symbolMode | SAR | AED | OMR | 用途 |
|---|---|---|---|---|
auto (デフォルト) | ر.س | U+20C3 | U+20C4 | デフォルト。AED/OMR には専用記号を使用し、SAR は安全なテキスト表記のままです |
new | U+20C1 | U+20C3 | U+20C4 | 専用記号を強制します(フォントのサポートが必要です) |
text | ر.س | د.إ | ر.ع. | 常に安全なテキスト記号を使用します。あらゆる環境で表示されます |
code | SAR | AED | OMR | ISO コード |
Unicode 18.0(2026 年 9 月 16 日): AED(U+20C3)、OMR(U+20C4)、MVR (U+20C2)の記号は
liveになり、autoはこれらを優先します。現時点で 最大限の互換性が必要ですか?symbolMode: "text"を使用してください。サウジアラビア・リヤルは、 設計上、安全なテキスト表記をデフォルトとしています。全一覧については、 移行に関するセクションをご覧ください。
正確な小数桁数 — アラブ連盟の全 22 か国
ビルド時に CLDR 48.2.0 から生成され、ビルドのたびに検証されます。
formatCurrency(1.2, { currency: "KWD" }); // "1.200 د.ك" ← 3 decimals
formatCurrency(1.2, { currency: "BHD" }); // "1.200 د.ب" ← 3 decimals
formatCurrency(1.2, { currency: "IQD" }); // "1.200 ع.د" ← 3 decimals (ISO 4217, not CLDR's 0)
formatCurrency(500, { currency: "KMF" }); // "500 ف.ج.ق" ← 0 decimals
formatCurrency(500, { currency: "SAR" }); // "500.00 ر.س" ← 2 decimals
| 小数桁数 | 通貨 |
|---|---|
| 3 | KWD、BHD、OMR、JOD、IQD、LYD、TND |
| 0 | DJF、KMF |
| 2 | SAR、AED、QAR、およびその他 |
通貨オプション一覧
// Resolve from locale region — no need to know the currency code
formatCurrency(99.9, { locale: "ar-BH" }); // "99.900 د.ب"
formatCurrency(1234, { locale: "ar-AE", numerals: "arab", symbolMode: "text" }); // "١٬٢٣٤٫٠٠ د.إ" (auto → U+20C3 sign)
// Accounting notation (negatives in parentheses)
formatCurrency(-1234.5, { currency: "SAR", accounting: true }); // "(1,234.50 ر.س)"
// Hide/override
formatCurrency(100, { currency: "SAR", showSymbol: false, fractionDigits: 0 }); // "100"
// Currency metadata
getCurrencyInfo("SAR");
// {
// code: "SAR", digits: 2,
// symbols: { auto: "ر.س", text: "ر.س", code: "SAR", new: "" },
// unicode: { codepoint: "U+20C1", unicodeVersion: "17.0", live: true, autoDefault: false },
// displayName: "ريال سعودي"
// }
価格帯
import { formatCurrencyRange } from "arabicfmt/currency";
formatCurrencyRange(1000, 5000, { currency: "SAR" })
// "1,000.00 – 5,000.00 ر.س" ← one symbol, the way ranges are actually set
formatCurrencyRange(1000, 5000, { currency: "SAR", symbolEach: true })
// "1,000.00 ر.س – 5,000.00 ر.س"
formatCurrencyRange(1.2, 2, { currency: "KWD" })
// "1.200 – 2.000 د.ك" ← both ends share the currency's precision
formatCurrencyRange(1000, 5000, { currency: "SAR", numerals: "arab" })
// "١٬٠٠٠٫٠٠ – ٥٬٠٠٠٫٠٠ ر.س"
formatCurrencyRange(50, 50, { currency: "AED" }) // "50.00 " — collapses
formatCurrencyRange(500, 100, { currency: "SAR" }) // throws: reversed range
デフォルトのスペース付きエンダッシュ以外を使う場合は rangeSeparator({ rangeSeparator: " إلى " })を指定し、混在する方向の文中に範囲全体を配置する場合は isolate: true を指定してください。
新しい記号のレンダリング
新しい記号には、文字列だけでは用意できないものが2つ必要です。コードポイントにスコープを限定したウェブフォントと、そのフォントを使う要素で 記号だけ を囲む方法です。どちらも1回の呼び出しで実現できます。
1. parts API — 通貨版の
Intl.NumberFormat.prototype.formatToParts です。
import { formatCurrencyToParts } from "arabicfmt/currency";
formatCurrencyToParts(1234.5, { currency: "SAR", symbolMode: "new" });
// [ { type: "integer", value: "1" },
// { type: "group", value: "," },
// { type: "integer", value: "234" },
// { type: "decimal", value: "." },
// { type: "fraction", value: "50" },
// { type: "literal", value: " " },
// { type: "currency", value: "", symbolMode: "new",
// codepoint: "U+20C1", needsFont: true } ]
needsFont は、パーツに専用の Unicode 記号が含まれる場合に限り true になるため、コンポーネントで完成した文字列をパターンマッチする必要はありません(これが bidi の不具合の原因になります)。
<span dir="rtl">
{formatCurrencyToParts(total, { currency: "SAR", symbolMode: "new" }).map(
(part, i) =>
part.needsFont
? <span key={i} className="riyal-sign">{part.value}</span>
: <span key={i}>{part.value}</span>,
)}
</span>
パーツの型は Intl の型(integer、group、decimal、fraction、
minusSign、plusSign、literal)に加え、arabicfmt が追加する4つの型、currency、parenthesis(会計形式)、isolate(bidi 制御文字)、rangeSeparator を反映しています。
2. @font-face ルール — 生成されるルールには unicode-range が指定されており、記号を表示しないページではコストがかかりません。
import { signFontFaceCSS } from "arabicfmt/currency";
signFontFaceCSS({ src: "/fonts/currency-signs.woff2" });
// @font-face {
// font-family: "Arabicfmt Signs";
// src: url("/fonts/currency-signs.woff2") format("woff2");
// font-display: swap;
// unicode-range: U+20C1, U+20C2, U+20C3, U+20C4;
// }
// Saudi riyal only, into a family name you already use:
signFontFaceCSS({ src: "/fonts/riyal.woff2", family: "Riyal", currencies: ["SAR"] });
// unicode-range: U+20C1;
この範囲は該当するコードポイントに限定されているため、ブラウザーがフォントをダウンロードするのは、そのいずれかが実際に描画されるときだけです。本文テキストには影響しません。フォントスタックの先頭にファミリーを置けば、残りはフォールバックします。
:root { font-family: "Arabicfmt Signs", "Noto Naskh Arabic", sans-serif; }
signUnicodeRange() は、CSS-in-JS 用に範囲文字列("U+20C1, U+20C2, U+20C3, U+20C4")だけを返します。どちらのヘルパーも、ルールの外部へ抜け出す可能性のある値を拒否するため、設定の URL から CSS を注入することはできません。
数値のフォーマット
import {
formatNumber, formatCompact, formatPercent,
toArabicDigits, toExtendedArabicDigits, toLatinDigits,
parseNumber, parseCurrency,
arabicToWords,
formatRelativeTime,
} from "arabicfmt/number";
// Standard
formatNumber(1_234_567.89, { locale: "en" }); // "1,234,567.89"
formatNumber(1234.5, { numerals: "arab" }); // "١٬٢٣٤٫٥"
// Compact / short notation — dashboards and data cards
formatCompact(1_500_000); // "1.5M"
formatCompact(1_500_000, { locale: "ar" }); // "1.5 مليون"
formatCompact(1_500_000, { locale: "ar", numerals: "arab" }); // "١٫٥ مليون"
// Percent
formatPercent(0.853, { locale: "en" }); // "85.3%"
// Three numeral systems: latn (default), arab, arabext
formatNumber(1234.5, { numerals: "arab" }); // "١٬٢٣٤٫٥" Eastern Arabic
formatNumber(1234.5, { numerals: "arabext" }); // "۱٬۲۳۴٫۵" Persian/Urdu
// Transliteration
toArabicDigits("Order #2026"); // "Order #٢٠٢٦"
toExtendedArabicDigits("2026"); // "۲۰۲۶"
toLatinDigits("٢٠٢٦"); // "2026" (handles Persian ۰–۹ too)
// Parsing — round-trip support
parseNumber("١٬٢٣٤٫٥٦"); // 1234.56 (Eastern Arabic digits + separators)
parseNumber("1,234.56"); // 1234.56 (Western)
parseCurrency("١٬٢٣٤٫٥٠ ر.س"); // 1234.5
parseCurrency("(500.00 SAR)"); // -500 (accounting notation)
// Relative time
formatRelativeTime(new Date(Date.now() - 3 * 86400_000)); // "منذ 3 أيام"
formatRelativeTime(new Date(Date.now() + 3600_000), new Date(), { locale: "en" }); // "in 1 hour"
数値をアラビア語の単語に変換(arabicToWords)
整数をアラビア語の単語表記に変換します。性の一致と6段階すべての数の単位に対応します。
import { arabicToWords } from "arabicfmt";
// Basic
arabicToWords(0) // "صفر"
arabicToWords(1) // "واحد"
arabicToWords(2) // "اثنان"
arabicToWords(11) // "أحد عشر"
arabicToWords(25) // "خمسة وعشرون"
arabicToWords(100) // "مئة"
arabicToWords(350) // "ثلاثمئة وخمسون"
// Thousands
arabicToWords(1000) // "ألف"
arabicToWords(2000) // "ألفان"
arabicToWords(5000) // "خمسة آلاف"
arabicToWords(11000) // "أحد عشر ألفاً"
arabicToWords(100000) // "مئة ألف"
// Millions / billions
arabicToWords(1_000_000) // "مليون"
arabicToWords(2_000_000) // "مليونان"
arabicToWords(5_000_000) // "خمسة ملايين"
arabicToWords(1_000_000_000)// "مليار"
// Large composite
arabicToWords(1_234_567)
// "مليون ومئتان وأربعة وثلاثون ألفاً وخمسمئة وسبعة وستون"
// Gender agreement — feminine noun (ليرة، روبية…)
arabicToWords(3, { gender: "female" }) // "ثلاث"
arabicToWords(5, { gender: "female" }) // "خمس"
// Negative
arabicToWords(-42) // "سالب اثنان وأربعون"
// Decimals — opt in (default truncates, stays backward compatible)
arabicToWords(3.14, { fraction: "digits" }) // "ثلاثة فاصلة واحد أربعة"
arabicToWords(3.14, { fraction: "number" }) // "ثلاثة فاصلة أربعة عشر"
// Common fractions (denominators 2–10)
import { arabicFraction } from "arabicfmt";
arabicFraction(1, 2) // "نصف"
arabicFraction(3, 4) // "ثلاثة أرباع"
arabicFraction(2, 3) // "ثلثان"
金額を単語で表記 — التفقيط
spellCurrency は、アラビア語の請求書、小切手、契約書に必要な tafqit です。数値の金額を正式なアラビア語表記に変換し、主要単位と補助単位に分けたうえで、文法上の一致(単数/双数/複数/対格)が正しくなるよう、すべての名詞を活用します。
import { spellCurrency } from "arabicfmt";
spellCurrency(1234.5, { currency: "SAR" })
// "ألف ومئتان وأربعة وثلاثون ريالاً وخمسون هللةً"
// Unit agreement is automatic (العدد والمعدود)
spellCurrency(1, { currency: "SAR" }) // "ريال واحد" (singular)
spellCurrency(2, { currency: "SAR" }) // "ريالان" (dual)
spellCurrency(3, { currency: "SAR" }) // "ثلاثة ريالات" (plural, 3–10)
spellCurrency(11, { currency: "SAR" }) // "أحد عشر ريالاً" (accusative, 11–99)
spellCurrency(100, { currency: "SAR" }) // "مئة ريال" (genitive singular)
// Minor-unit precision comes from CLDR — KWD = 1000 fils, SAR = 100 halalas
spellCurrency(1.5, { currency: "KWD" }) // "دينار واحد وخمسمئة فلس"
spellCurrency(0.75, { currency: "SAR" }) // "خمس وسبعون هللةً"
// Cheque-ready ending and locale-derived currency
spellCurrency(100, { currency: "SAR", suffix: true }) // "مئة ريال فقط لا غير"
spellCurrency(-5, { locale: "ar-AE" }) // "سالب خمسة دراهم"
アラブ連盟加盟国の全22通貨(SAR、AED、KWD、BHD、QAR、OMR、JOD、EGP、IQD、LYD、TND、DZD、MAD、SDG、LBP、SYP、YER、SOS、DJF、KMF、MRU)について、アラビア語の名詞の完全な活用形を同梱しています。エクスポートされる CURRENCY_WORDS テーブルから確認または拡張できます。
序数 — الأعداد الترتيبية
import { arabicOrdinal } from "arabicfmt";
arabicOrdinal(1) // "الأول"
arabicOrdinal(2) // "الثاني"
arabicOrdinal(10) // "العاشر"
arabicOrdinal(11) // "الحادي عشر"
arabicOrdinal(25) // "الخامس والعشرون"
// Gender agreement
arabicOrdinal(1, { gender: "female" }) // "الأولى"
arabicOrdinal(25, { gender: "female" }) // "الخامسة والعشرون"
// Indefinite (drop the article ال)
arabicOrdinal(3, { definite: false }) // "ثالث"
arabicOrdinal(25, { definite: false }) // "خامس وعشرون"
期間 — アラビア語の綴り
formatDuration は期間を話し言葉のアラビア語表記に変換し、各単位について双数/複数/対格の一致を正しく処理します。これは、まだサポートがほとんど進んでいない Intl.DurationFormat では実現できません。
import { formatDuration } from "arabicfmt";
formatDuration(7_500_000) // "ساعتان وخمس دقائق" (2h 5m)
formatDuration(90, { input: "s" }) // "دقيقة واحدة وثلاثون ثانيةً"
formatDuration(3_600_000, { largest: 1 }) // "ساعة واحدة"
formatDuration(2 * 86_400_000) // "يومان"
formatDuration(500) // "أقل من ثانية"
// Restrict the units considered
formatDuration(125 * 60_000, { units: ["minute"], largest: 1 })
// "مئة وخمس وعشرون دقيقةً"
largest(デフォルトは 2)で、表示する単位数の上限を指定します。大きい単位から表示されます。名詞の一致を自分で制御したい場合は、任意の数えられる名詞に使える countedNoun(n, forms) がエクスポートされています。
ファイルサイズ — アラビア語のデータ単位
import { formatFileSize } from "arabicfmt";
formatFileSize(0) // "0 بايت"
formatFileSize(1536) // "1.5 كيلوبايت"
formatFileSize(5 * 1024 * 1024) // "5 ميجابايت"
formatFileSize(1_500_000, { base: 1000 }) // "1.5 ميجابايت" (decimal/SI)
formatFileSize(2048, { numerals: "arab" }) // "٢ كيلوبايت"
formatFileSize(2048, { unitStyle: "latin" })// "2 KB"
単位は بايت · كيلوبايت · ميجابايت · جيجابايت · تيرابايت · بيتابايت とスケールし、base: 1024(2進数、デフォルト)または base: 1000(10進数)を指定できます。
アラビア語の複数形ルール(6形式)
アラビア語には6つの複数形があります。これは他の主要言語よりも多い数です。標準的な i18n ライブラリは1〜2形式にしか対応していないため、アラビア語では正しく動作しません。
import { arabicPluralForm, arabicPlural } from "arabicfmt";
// Get the CLDR form name
arabicPluralForm(0) // "zero"
arabicPluralForm(1) // "one"
arabicPluralForm(2) // "two"
arabicPluralForm(5) // "few" (3–10)
arabicPluralForm(15) // "many" (11–99)
arabicPluralForm(100) // "other"
// Select the right string
const forms = {
zero: "لا كتب",
one: "كتاب واحد",
two: "كتابان",
few: "كتب", // 3–10
many: "كتاباً", // 11–99
other: "كتاب",
};
arabicPlural(0, forms) // "لا كتب"
arabicPlural(1, forms) // "كتاب واحد"
arabicPlural(2, forms) // "كتابان"
arabicPlural(5, forms) // "كتب"
arabicPlural(25, forms) // "كتاباً"
arabicPlural(100, forms) // "كتاب"
ヒジュラ暦/イスラム暦の日付
同一の API を持つ2つのエンジンがあります。
arabicfmt/date | arabicfmt/umalqura | |
|---|---|---|
| アルゴリズム | 表形式の算術 | 公式のウンム・アルクラー暦テーブル |
| 精度 | ±1~2日 | 正確 |
| バンドル | 小(テーブルなし) | 大(固定された ICU テーブル) |
| 範囲 | 任意の年 | AH 1300~1599 |
| 決定性 | あり | あり — Node/Chrome/Safari/Hermes で同一 |
import { toHijri, fromHijri, formatHijri, umalquraToGregorian } from "arabicfmt/umalqura";
// Convert
toHijri(new Date("2025-09-23")) // { year: 1447, month: 4, day: 1 }
umalquraToGregorian(1447, 9, 1) // JavaScript Date — first day of Ramadan 1447
// Format — Arabic
formatHijri(new Date("2025-09-23"))
// "1 ربيع الآخر 1447 هـ"
formatHijri(new Date("2025-09-23"), { numerals: "arab" })
// "١ ربيع الآخر ١٤٤٧ هـ"
// Format — English
formatHijri(new Date("2025-09-23"), { locale: "en" })
// "1 Rabi al-Thani 1447 AH"
// Format — ISO-style numeric
formatHijri(new Date("2025-09-23"), {
locale: "en", month: "2-digit", day: "2-digit", order: "ymd", era: false,
})
// "1447/04/01"
月名と曜日名のテーブル
import {
HIJRI_MONTHS_AR, // Arabic Hijri month names
HIJRI_MONTHS_EN, // English Hijri month names
GREGORIAN_MONTHS_AR, // Arabic Gregorian month names (يناير، فبراير…)
GREGORIAN_MONTHS_EN,
ARABIC_WEEKDAYS_AR, // Arabic weekday names (الأحد، الاثنين…)
ARABIC_WEEKDAYS_EN,
} from "arabicfmt/date";
HIJRI_MONTHS_AR[8] // "رمضان" (index 0 = Muharram)
GREGORIAN_MONTHS_AR[0] // "يناير" (index 0 = January)
ARABIC_WEEKDAYS_AR[5] // "الجمعة" (index 0 = Sunday)
双方向(RTL)テキストのヘルパー
電話番号や英単語によってアラビア語の文が乱れるのを防ぎます。
import { detectDirection, isolate, isolateForeign, stripBidi } from "arabicfmt/bidi";
// Before fix: "+1 (555) 234-5678" flips the area code in RTL context
// After fix: the phone number is wrapped in Unicode isolates — sentence intact
isolateForeign("اتصل على +1 (555) 234-5678 الآن");
detectDirection("مرحبا"); // "rtl"
detectDirection("Hello"); // "ltr"
isolate("9:41 AM"); // FSI … PDI isolate around a mixed run
stripBidi(dirtyStr); // remove every Unicode bidi control character
アラビア語検索向けテキスト正規化
発音区別符号、アレフの異形、ハムザ、ター・マルブータの違いがあっても、アラビア語テキストを照合できます。
import {
stripTashkeel,
normalizeArabic,
normalizeForSearch,
sortArabic,
compareArabic,
} from "arabicfmt/text";
stripTashkeel("مُحَمَّد") // "محمد"
normalizeArabic("الأحمد") // "الاحمد" (alef variants unified)
// Robust search — these two strings produce the same key:
normalizeForSearch("مُؤسَّسة") === normalizeForSearch("موسسه") // true
// Arabic-locale collation
sortArabic(["ياسر", "أحمد", "بسام"]) // ["أحمد", "بسام", "ياسر"]
["ج", "أ", "ب"].sort(compareArabic) // ["أ", "ب", "ج"]
リストのフォーマット
文法的に正しいアラビア語のリストになるよう、値を連結します。Intl.ListFormat をラップし、対応していないランタイムでも適切に動作します。
import { formatList } from "arabicfmt";
formatList(["أحمد", "محمد", "علي"]) // "أحمد ومحمد وعلي"
formatList(["تفاح", "موز", "برتقال"], { type: "disjunction" }) // "تفاح أو موز أو برتقال"
formatList([1, 2, 3], { numerals: "arab" }) // "١ و٢ و٣"
翻字と URL スラッグ
アラビア文字を読みやすいラテン文字に翻字したり、ルート、ファイル名、CMS パーマリンク向けに URL で安全に使えるスラッグに変換したりできます。決定的な変換です。短母音が現れるのは、テキストに母音記号(タシュキール)が付いている場合のみです。
import { transliterate, slugify } from "arabicfmt";
transliterate("مُحَمَّد") // "muhammad" (vowelled)
transliterate("محمد") // "mhmd" (bare → consonant-only)
transliterate("الرياض") // "alryad"
transliterate("غرفة ٢٠١") // "ghrfh 201" (digits converted)
slugify("مدينة جدة") // "mdynh-jdh"
slugify("الرياض 2026") // "alryad-2026"
slugify("Hello العالم", { separator: "_" }) // "hello_alalm"
slugify("Hello World", { lowercase: false }) // "Hello-World"
注:これは実用性を重視した、ある程度可逆な翻字であり、厳密な学術的翻字(DIN 31635 / ISO 233)ではありません。スラッグ、検索キー、読みやすい ID 向けに作られています。
検証 — IBAN とサウジアラビア ID
正規表現による推測ではなく、実際のチェックサムを使用します。isValidIBAN は SWIFT レジストリの長さチェックとともに ISO 7064 の mod-97
アルゴリズムを実行します。isValidSaudiId は Luhn チェックディジットを確認し、市民か居住者かを分類します。
import { isValidIBAN, formatIBAN, isValidSaudiId, saudiIdType } from "arabicfmt";
isValidIBAN("SA03 8000 0000 6080 1016 7519") // true
isValidIBAN("SA03 8000 0000 6080 1016 7510") // false (bad checksum)
formatIBAN("SA0380000000608010167519") // "SA03 8000 0000 6080 1016 7519"
isValidSaudiId("1012345672") // true
saudiIdType("1012345672") // "citizen"
saudiIdType("2100000005") // "resident" (Iqama)
SA、AE、KW、BH、QA、JO、LB、EG、IQ、PS、TN、MR、 LY(および一般的な提携国)について、レジストリで定められた長さを適用します。未知の国の IBAN はチェックサムと 一般的な長さの範囲(15~34文字)で検証され、構造だけを根拠に有効と判定されることはありません。
フレームワークでの使用
React / Next.js
import { formatCurrency, detectLocale } from "arabicfmt";
import { formatHijri } from "arabicfmt/umalqura";
export function PriceTag({ amount, currency }: { amount: number; currency: string }) {
const locale = detectLocale();
return (
<span dir="rtl">
{formatCurrency(amount, { currency, locale })}
</span>
);
}
export function HijriDate({ date }: { date: Date }) {
return <time>{formatHijri(date, { numerals: "arab" })}</time>;
}
Vue 3
import { formatCurrency } from "arabicfmt";
// composable
export function useArabicCurrency(currency: string) {
return (amount: number) =>
formatCurrency(amount, { currency, numerals: "arab" });
}
Node.js / Express
import { formatCurrency, detectLocale } from "arabicfmt";
import { formatHijri } from "arabicfmt/umalqura";
app.get("/invoice/:id", (req, res) => {
const locale = req.headers["accept-language"]?.split(",")[0] ?? "ar-SA";
const total = formatCurrency(order.total, { locale });
const date = formatHijri(order.date, { locale: "ar" });
res.json({ total, date });
});
ロケールの自動検出
import { detectLocale } from "arabicfmt";
// Browser: reads navigator.language
// Node.js: reads LANG / LANGUAGE / LC_ALL / LC_MESSAGES env vars
// Fallback: "ar"
const locale = detectLocale(); // "ar-SA", "ar-EG", "en-US", …
formatCurrency(1234, { locale });
サブパスインポート — ツリーシェイキング対応
必要なものだけを選択して、バンドルをできる限り小さくできます。
import { formatCurrency, spellCurrency } from "arabicfmt/currency";
import { formatNumber, arabicToWords, formatDuration, formatFileSize } from "arabicfmt/number";
import { formatHijri, toHijri } from "arabicfmt/date"; // tabular core (tiny)
import { formatHijri, toHijri } from "arabicfmt/umalqura"; // accurate, opt-in
import { isolateForeign } from "arabicfmt/bidi";
import { normalizeForSearch, arabicPlural, slugify } from "arabicfmt/text";
import { isValidIBAN, isValidSaudiId } from "arabicfmt/validate";
各エントリーポイントの測定サイズ(esbuild --bundle --minify、gzip 圧縮後 — v0.1.5):
| インポート | 内容 | min + gzip |
|---|---|---|
arabicfmt | 以下のすべて | 13.2 kB |
arabicfmt/currency | 22種類の通貨、تفقيط、パーツ、範囲、通貨切り替えレジストリ | 7.6 kB |
arabicfmt/number | 数詞、序数、分数、パース、時間、… | 3.6 kB |
arabicfmt/umalqura | 公式のウム・アルクラー暦テーブル300年分 | 2.4 kB |
arabicfmt/text | 正規化、複数形、照合、リスト、スラッグ | 1.7 kB |
arabicfmt/date | 表形式ヒジュラ暦のコア機能 | 1.6 kB |
arabicfmt/bidi | 方向の検出 + 分離記号 | 0.8 kB |
arabicfmt/validate | IBAN + サウジアラビア ID のチェックサム | 0.7 kB |
アラビア語のフォーマット機能一式のサイズは、小さな画像1枚分より小さいです。
API リファレンス全文
モジュールごとに、すべての公開関数を掲載しています。完全なシグネチャとオプションは、上記の各セクションと同梱の TypeScript 型定義に記載されています。
| モジュール | 関数 |
|---|---|
arabicfmt/currency | formatCurrency · formatCurrencyToParts · formatCurrencyRange · spellCurrency · getCurrencyInfo · resolveCurrencySymbol · transitionStatus · getCurrencyTransition · listCurrencyTransitions · signFontFaceCSS · signUnicodeRange |
arabicfmt/number | formatNumber · formatPercent · formatCompact · parseNumber · parseCurrency · toArabicDigits · toExtendedArabicDigits · toLatinDigits · shapeDigits · arabicToWords · arabicOrdinal · arabicFraction · countedNoun · formatDuration · formatFileSize · formatRelativeTime |
arabicfmt/umalqura | formatHijri · toHijri · fromHijri · gregorianToUmalqura · umalquraToGregorian |
arabicfmt/date | formatHijri · toHijri · fromHijri (表形式のコア機能) |
arabicfmt/text | stripTashkeel · removeTatweel · normalizeArabic · normalizeForSearch · arabicPlural · arabicPluralForm · sortArabic · compareArabic · createArabicCollator · formatList · transliterate · slugify |
arabicfmt/bidi | isolateForeign · isolate · wrapLTR · wrapRTL · stripBidi · detectDirection · isRTL · charDirection |
arabicfmt/validate | isValidIBAN · formatIBAN · normalizeIBAN · isValidSaudiId · saudiIdType |
arabicfmt (ルート) | 上記すべてを再エクスポート + detectLocale |
MCP サーバー — AI エージェントから arabicfmt を使用する
AI エージェント(Claude Desktop、Claude Code、Cursor)は、Model Context Protocol サーバー
arabicfmt-mcp を通じて arabicfmt を直接呼び出せます —
21個のツール(format_currency、format_currency_range、currency_transition、
spell_currency、format_hijri、arabic_to_words、isolate_foreign、
validate_iban、…)。クライアントの mcpServers 設定に追加してください。
{
"mcpServers": {
"arabicfmt": { "command": "npx", "args": ["-y", "arabicfmt-mcp"] }
}
}
ソースとツール一覧:mcp/。
使用例
すべての機能を実行できるスクリプトは、examples/ にあります。
cd examples && npm install
node currency.mjs # or numbers / words / dates / text / bidi / validate
エンジニアリング
| 依存関係 | 実行時依存関係なし |
| サイズ | ライブラリ全体で圧縮後約 13.2 kB、サブパスインポートは 0.7 kB から |
| フォーマット | ESM と CJS の両方に対応し、.d.ts / .d.cts 型定義を完備 |
| ツリーシェイキング | "sideEffects": false — インポートした分だけ使用します |
| データソース | CLDR 48.2.0 + ICU — 手入力ではなく、ビルド時に検証済み |
| テストカバレッジ | 242 件のテスト — 通貨の移行、パーツ、範囲、精度、ヒジュラ暦、複数形、単語、tafqit、期間、IBAN/ID |
| プラットフォーム | Node ≥ 18、現行の主要ブラウザーすべて、React Native / Hermes、Deno、Bun |
| 公開方法 | npm provenance(GitHub Actions attestation) |
Unicode 通貨記号の移行
Unicode 18.0 の時点で完了 — 2026 年 9 月 16 日リリース
このサイクルでは、4 つの通貨が独自の略記から専用の Unicode 記号へ移行し、arabicfmt はそのすべてに対応しています。この一覧にないものにもご注意ください。クウェートはディナール記号を発行したことがありません。KWD は引き続き د.ك / KD であり、transitionStatus("KWD") は "none" を返します。
| 通貨 | 記号 | コードポイント | Unicode | 発表 | auto の既定値 |
|---|---|---|---|---|---|
| サウジアラビア・リヤル(SAR) | | U+20C1 | 17.0(2025 年 9 月 9 日) | SAMA、2025 年 2 月 20 日 | テキスト ر.س(保守的) |
| モルディブ・ルフィヤ(MVR) | | U+20C2 | 18.0(2026 年 9 月 16 日) | MMA、2022 年 7 月 3 日 | 記号 |
| UAE ディルハム(AED) | | U+20C3 | 18.0(2026 年 9 月 16 日) | CBUAE、2025 年 3 月 27 日 | 記号 |
| オマーン・リアル(OMR) | | U+20C4 | 18.0(2026 年 9 月 16 日) | CBO、2025 年 11 月 19 日 | 記号 |
ルフィヤはアラブ連盟の通貨ではありませんが、同じ一括登録で追加され、Currency Symbols ブロックではディルハムとリアルの間に位置します。これを含めることで範囲が連続し、1 つの unicode-range で移行全体をカバーできます。
新しい記号へのシステムフォントの対応状況はまださまざまであるため、symbolMode: "text" は常に安全な略記を返します。また、設計上、サウジアラビア・リヤルはテキスト記号を auto の既定値としています。
データとしての移行
符号化されていることと、表示されることは別です。記号が標準に登録されてからシステムフォントで描画されるまで、数カ月、あるいは数年かかることがあります。その期間にリリースされる各製品は、何を表示するか決める必要があります。このタイムラインは照会できます。
import {
transitionStatus,
listCurrencyTransitions,
getCurrencyTransition,
} from "arabicfmt/currency";
transitionStatus("SAR") // "encoded"
transitionStatus("SAR", new Date("2025-03-01")) // "announced" — SAMA had it, Unicode didn't
transitionStatus("AED", new Date("2026-01-01")) // "announced"
transitionStatus("KWD") // "none" — no sign exists
listCurrencyTransitions({ unicodeVersion: "18.0" }).map((t) => t.code);
// ["MVR", "AED", "OMR"]
getCurrencyTransition("OMR");
// {
// code: "OMR", sign: "", codepoint: "U+20C4", name: "OMANI RIAL SIGN",
// unicodeVersion: "18.0", unicodeReleased: "2026-09-16",
// announced: "2025-11-19", authority: "Central Bank of Oman (CBO)",
// autoDefault: true, textSymbol: "ر.ع.",
// }
transitionStatus は時点を受け取るため、過去の請求書を、その日付に正しかった記号で再表示できます。
ライブデモ
arabicfmt.vercel.app — ライブラリ全体を、ブラウザー上でインタラクティブにリアルタイム計算できます。入力を変更すると、アラビア語の表示がすぐに更新されます。通貨スタジオ、تفقيط、ヒジュラ暦コンバーター、複数形、RTL の修正などに対応しています。
ローカルで実行するには:
cd demo && npm install && npm run dev
コントリビューション
GitHub でのイシューやプルリクエストを歓迎します。
ライセンス
MIT — 商用・個人利用ともに無料です。
作者とその他のプロジェクト
cc1a2b が開発・メンテナンスしています。
arabicfmt が時間の節約に役立ったら、ぜひ GitHub でスターを付けてください。ほかのアラビア語開発者が見つけやすくなります。**その他のオープンソースプロジェクト**もご覧ください。また、アイデア、不具合、機能リクエストがあれば、イシューを作成してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。

