Skip to content

Все для WordPress, веб-розробки — і не тільки

🔢 Переклад чисел з PHP і JavaScript: арабські цифри в деванагарі та назад

🔢 Переклад чисел з PHP і JavaScript: арабські цифри в деванагарі та назад

Користувач заповнює форму на сайті, і цифри перетворюються на нечитабельні символи. Знайома ситуація для тих, хто працює з мультимовними проєктами: непальська версія інтернет-магазину показує ціни в अक्षर, а форма зворотного зв'язку не проходить валідацію через «неправильні» цифри.

Проблема в тому, що різні мови використовують різні системи числових символів. Англійська та російська, арабські цифри (0-9). Гінді, непальська, маратхі, символи деванагарі (०-९). PHP і JavaScript «з коробки» не перемикаються між ними. При цьому задача вирішується без жодної зовнішньої бібліотеки, вистачає вбудованих функцій роботи з рядками. Жодних підключених залежностей, жодних сторонніх API.

Нижче, два готові фрагменти коду, які закривають питання за 5 хвилин. Без фреймворків, без Composer-пакетів, без npm-залежностей, на чистому PHP і ванільному JavaScript. Скопіювали, підставили свої символи, запрацювало.

💡 Швидкий огляд:

  • Скопіюйте PHP-функцію у functions.php теми або через плагін Code Snippets, вона переводить арабські цифри в деванагарі та назад
  • Для фронтенду використовуйте готовий JavaScript-код з об'єктами-словниками, конвертація на льоту прямо в полі введення
  • Заміна йде за таблицею відповідності гліфів, а не математично, метод універсальний для будь-якої писемності
  • Протестуйте: передайте 1234 і отримайте १२३४, і навпаки, обидві сторони працюють симетрично

Як влаштовані числові системи в різних мовах

Більшість сайтів працює з арабськими цифрами: 0 1 2 3 4 5 6 7 8 9. Історично ця система прийшла з Індії, але закріпилася через арабський світ, звідси й назва.

Альтернативні набори існують у десятках писемностей. Деванагарі (гінді, непальська, маратхі) використовує власний ряд: ० १ २ ३ ४ ५ ६ ७ ८ ९. Східноарабські цифри (арабська, перська, урду), інший набір: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩. Бенгальська, тайська, кхмерська: у кожної свої гліфи та свої діапазони в таблиці Unicode. Загалом таких систем понад двадцять.

Але числове значення залишається тим самим. 5, і ٥ — це одне й те саме число «п'ять», просто записане різними символами. Тому переклад між системами — це заміна гліфів за таблицею відповідності, а не математична конвертація. Нічого перераховувати не потрібно, достатньо знати правильні пари символів.

Саме цей принцип і закладено в коді нижче.

Крок 1: Переклад чисел за допомогою PHP

Програміст працює за ноутбуком з відкритим редактором коду

PHP-підхід максимально простий: функція str_replace() приймає два масиви, що шукати і на що замінювати. Рядок проходить один прохід, і всі збіги замінюються.

Додайте цей код у functions.php дочірньої теми або через плагін Code Snippets. Функція приймає число або рядок із цифрами та повертає результат із символами деванагарі.

1<?php
2/**
3 * Конвертирует арабские цифры в символы деванагари (хинди, непальский).
4 *
5 * @param string|int $input Строка или число для конвертации.
6 * @return string Строка с цифрами деванагари.
7 */
8function convert_to_devanagari($input) {
9 $english = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
10 $devanagari = array("०", "१", "२", "३", "४", "५", "६", "७", "८", "९");
11
12 return str_replace($english, $devanagari, (string) $input);
13}
14
15/* Пример использования */
16echo convert_to_devanagari(2026);
17// Вывод: २०२६
18?>

Що тут відбувається: str_replace() іде по масиву $english і для кожного елемента (наприклад, "2") підставляє відповідний елемент із $devanagari ("२"). Приведення до (string) гарантує, що функція відпрацює і з числом, і з рядком.

Зворотна конвертація, з деванагарі в арабські цифри, робиться перестановкою масивів місцями:

1<?php
2/**
3 * Конвертирует символы деванагари обратно в арабские цифры.
4 *
5 * @param string $input Строка с цифрами деванагари.
6 * @return string Строка с арабскими цифрами.
7 */
8function convert_from_devanagari($input) {
9 $english = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
10 $devanagari = array("०", "१", "२", "३", "४", "५", "६", "७", "८", "९");
11
12 return str_replace($devanagari, $english, $input);
13}
14
15/* Пример */
16echo convert_from_devanagari('२०२६');
17// Вывод: 2026
18?>

Масиви ті самі, змінюється лише порядок аргументів. Перший масив тепер містить символи деванагарі (те, що шукаємо), другий, арабські цифри (на що замінюємо).

Де застосувати. Функція знадобиться в будь-якому місці теми, де виводяться числа: ціни товарів у WooCommerce, дати в блозі, нумерація сторінок. Огортайте виклик там, де потрібна локалізація цифр під конкретну аудиторію.

Обробка граничних випадків у PHP

Функція convert_to_devanagari() приймає string|int, але на практиці вхід може бути будь-яким. Що буде, якщо передати null, порожній рядок або рядок без цифр? (string) null дасть порожній рядок, str_replace() із порожнім рядком теж поверне порожній, помилки не буде. Рядок без цифр (наприклад, "Привет") повернеться без змін, заміна просто не знайде збігів.

Якщо число містить роздільники (коми для тисяч, крапку для дробової частини), вони залишаться на місці, заміняться лише самі цифри. Для чисел із рухомою крапкою ця поведінка коректна, але якщо формат чисел важливий і роздільники повинні змінюватися під локаль, додайте окрему обробку через number_format() до конвертації.

Для дуже довгих чисел (наприклад, 20-значні ідентифікатори) підхід працює без змін: str_replace() обробляє рядок будь-якої довжини, обмеження лише в доступній пам'яті PHP. Символи деванагарі займають по 3 байти в UTF-8, тому підсумковий рядок буде довшим за вихідний у байтах. Для підрахунку символів використовуйте mb_strlen(), а не strlen().

Крок 2: Переклад чисел за допомогою JavaScript

На фронтенді та сама логіка реалізується через об'єкти-словники та метод String.replace() із регулярним виразом. Це зручно для динамічних інтерфейсів: користувач вводить число в поле, а скрипт на льоту показує еквівалент у деванагарі.

Розмістіть цей код в окремому .js-файлі теми або через wp_add_inline_script у functions.php. Жодних залежностей, чистий ES5, працює навіть у старих браузерах.

1/**
2 * Словари для перевода между арабскими цифрами и деванагари.
3 */
4var englishToDevanagari = {
5 '0': '०', '1': '१', '2': '२', '3': '३', '4': '४',
6 '5': '५', '6': '६', '7': '७', '8': '८', '9': '९'
7};
8
9var devanagariToEnglish = {
10 '०': '0', '१': '1', '२': '2', '३': '3', '४': '4',
11 '५': '5', '६': '6', '७': '7', '८': '8', '९': '9'
12};
13
14/**
15 * Конвертирует арабские цифры в строке в символы деванагари.
16 * @param {string|number} input
17 * @returns {string}
18 */
19function toDevanagari(input) {
20 return String(input).replace(/[0-9]/g, function(match) {
21 return englishToDevanagari[match];
22 });
23}
24
25/**
26 * Конвертирует символы деванагари в арабские цифры.
27 * @param {string} input
28 * @returns {string}
29 */
30function fromDevanagari(input) {
31 return input.replace(/[०-९]/g, function(match) {
32 return devanagariToEnglish[match];
33 });
34}
35
36// Примеры:
37console.log(toDevanagari(9857)); // ९८५७
38console.log(fromDevanagari('१२३४')); // 1234

Ключовий момент, регулярний вираз /[0-9]/g. Прапорець g (global) змушує replace() обробити кожну цифру в рядку, а не лише першу. Анонімна функція-колбек отримує символ, що збігся, і повертає його еквівалент зі словника.

Для цифр деванагарі використовується діапазон [०-९], в Unicode ці символи йдуть підряд, тому регулярка працює коректно.

Де застосувати. Живе введення у формах (конвертація на льоту під час набору), відображення цін і дат у локалізованих версіях сайту, зворотна конвертація перед відправленням форми на сервер, щоб у базу завжди потрапляли арабські цифри.

Практичний приклад: форма зворотного зв'язку з конвертацією на льоту

Зберемо обидва підходи в робочу зв'язку. Припустімо, на непальській версії сайту є форма замовлення, де користувач вводить суму в деванагарі. Задача: показати введене число в обох системах для перевірки та відправити на сервер арабські цифри.

Розмітка форми містить <input> і блок попереднього перегляду. На кожне натискання клавіші в полі спрацьовує обробник input, який викликає toDevanagari() і виводить результат у сусідній <span>. Під час відправлення форми спрацьовує fromDevanagari(), і в тілі POST-запиту на сервер ідуть уже арабські цифри. Серверна частина на PHP отримує число в стандартному форматі та працює з ним як зазвичай, без додаткової конвертації.

Цей самий шаблон застосовний до полів цін, дат, номерів телефонів і будь-яких інших полів, де користувач очікує побачити рідну систему цифр, а система повинна зберігати уніфікований формат. Конвертація займає мікросекунди та не впливає на чуйність інтерфейсу.

Дивіться також: відео про числові системи в програмуванні

Для ширшого погляду на тему, як влаштовані системи числення в коді та як конвертувати між ними на JavaScript, подивіться цей розбір від Techno Geek. Охоплює двійкову, вісімкову та десяткову системи з готовим проєктом.

⁉️🤔 Часті запитання

Чи можна цим самим методом перекласти цифри на арабську (східноарабські символи)?

Так. Замініть масив деванагарі на східноарабські символи: array("٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"). Логіка та сама, str_replace() у PHP і словник із регуляркою в JS. Так само адаптується під бенгальську, тайську, кхмерську та будь-яку іншу писемність із власними цифровими гліфами.

Чи безпечно використовувати str_replace() для багатобайтових рядків у PHP?

Так, str_replace() коректно працює з UTF-8 і багатобайтовими символами, на відміну від strpos() або substr(), яким потрібні mbstring-аналоги. Символи деванагарі (, ) займають по 3 байти в UTF-8, але str_replace() обробляє їх побайтово-безпечно, тому що шукає точний бінарний збіг послідовності. Проблем не буде.

Що робити, якщо в рядку змішані арабські цифри та символи деванагарі?

Обидві функції обробляють лише свої діапазони. Якщо на вхід convert_to_devanagari() прийшов рядок "Цена: 500 रुपей", цифра 500 стане ५००, а текст залишиться незайманим. Зворотна функція convert_from_devanagari() зачепить лише деванагарі-цифри. Змішане введення обробляється коректно автоматично.

Як застосувати конвертацію до всіх чисел на сторінці WordPress без правки кожного шаблону?

Використовуйте JavaScript-підхід із кроку 2 і запустіть обхід DOM-вузлів під час завантаження сторінки. Знайдіть усі текстові вузли з цифрами (через TreeWalker або рекурсивний обхід childNodes), застосуйте toDevanagari() до вмісту. Для PHP-підходу на серверній стороні, фільтр на the_content або gettext, якщо числа вбудовані в переклади.

Де взяти таблиці символів для інших писемностей?

Авторитетне джерело, Unicode Consortium. Для цифр деванагарі це діапазон U+0966-U+096F. Східноарабські, U+0660-U+0669. Бенгальські, U+09E6-U+09EF. Достатньо скопіювати символи з таблиці та підставити в масиви, код міняти не доведеться.

Продуктивність та обмеження підходу

str_replace() із масивами з 10 елементів робить рівно 10 порівнянь для кожної позиції в рядку. Для типового рядка з 5-10 цифрами це 50-100 операцій, час виконання вимірюється мікросекундами. Для порівняння, підхід через preg_replace_callback() із регулярним виразом додає накладні витрати на компіляцію шаблону та виклик колбеку для кожного збігу. Різниця на малих рядках непомітна, але str_replace() виграє на великих обсягах.

Основне обмеження підходу в тому, що він замінює гліфи, а не семантику числа. Якщо знадобиться арифметика над числами в деванагарі (додавання, множення), символи деванагарі не будуть сприйняті PHP як числа. Завжди конвертуйте в арабські цифри перед математичними операціями та назад після. Це не недолік методу, а наслідок різниці між писемністю та числовим типом даних.

Ще один нюанс: метод передбачає однозначну відповідність «один гліф, одна цифра». Для писемностей, де числа записуються складеними лігатурами (як у деяких історичних системах), підхід із простою заміною не спрацює. Але для всіх сучасних індійських писемностей (деванагарі, бенгальська, гурмукхі, гуджараті, орія, тамільська, телугу, каннада, малаялам), а також для східноарабських цифр відповідність строго 1 до 1, і метод працює безвідмовно.

Що ставити в production: PHP, JavaScript чи обидва варіанти?

PHP-рішення, для випадків, коли числа повинні бути відрендерені в потрібній системі символів на сервері до відправлення HTML. Це правильно для SEO: пошуковик бачить контент одразу в цільовій локалі, а не арабські цифри, які потім підміняються скриптом. Для інтернет-магазину на WooCommerce це означає, що ціни в каталозі та картці товару індексуються з цифрами деванагарі, що позитивно впливає на ранжування в непальському та гінді-сегментах.

JavaScript-варіант, для динамічної взаємодії: поле введення з миттєвим попереднім переглядом, перемикання мови інтерфейсу без перезавантаження, конвертація даних форми перед відправленням. Він також незамінний для односторінкових застосунків (SPA), де сервер віддає JSON з арабськими цифрами, а фронтенд рендерить їх у локалі користувача.

На практиці добре працює зв'язка: PHP рендерить сторінку з локалізованими цифрами для індексації, а JavaScript підхоплює користувацьке введення та конвертує туди-назад на льоту. Обидва фрагменти коду, без зовнішніх залежностей, менше 40 рядків на двох, і закривають задачу повністю для будь-якої писемності з власними цифровими гліфами.

Перед викладкою в production перевірте три сценарії: прямий виклик функції з числом, рядок зі змішаним вмістом (цифри плюс текст) і зворотну конвертацію. Переконайтеся, що на сервер завжди потрапляють арабські цифри, а в інтерфейсі користувач бачить ту систему, яка відповідає його мовним очікуванням. П'ять хвилин на тестування економлять години налагодження на живому трафіку.

Скопіюйте обидва фрагменти коду в проєкт, підставте потрібні символи з таблиці Unicode під свою писемність, і задачу закрито. Все, що потрібно, вже вбудовано в мову.