Генератор slug

Превращает заголовок в slug для URL: транслитерация иврита, арабского, кириллицы и греческого, форма пути в Unicode и проверка совпадений.

Slug
creme-brulee-grusse-aus-munchen
Путь в Unicode — без транслитерации и без потерь
crème-brûlée-grüße-aus-münchen
Процентное кодирование — то, что видит сервер
cr%C3%A8me-br%C3%BBl%C3%A9e-gr%C3%BC%C3%9Fe-aus-m%C3%BCnchen

Браузер показывает читаемую форму выше, а отправляет эту. Это один и тот же путь.

Что делает этот инструмент

Вставьте заголовок в любой письменности — и он вернётся тем slug, который выдержит URL: строчные буквы, никакой пунктуации, слова соединены выбранным вами разделителем. Латинские диакритики снимаются, а иврит, арабский, кириллица и греческий транслитерируются в латинские буквы.

Рядом со slug стоит тот же заголовок, сохранённый в собственной письменности. Эта форма — тоже законный путь, и для письменностей, которые теряют при транслитерации больше всего, она часто оказывается лучшим ответом. Поэтому обе строятся из одного заголовка, а не выбираются инструментом за вас.

Зачем нужен slug

Slug — это читаемая человеком часть URL: кусок после последней косой черты, который называет страницу, а не нумерует её. Он существует потому, что путь, читающийся как слова, переживает вставку в сообщение, печать на слайде и чтение вслух по телефону, а числовой идентификатор не переживает ничего из этого.

По той же причине его форма так стеснена. Slug должен быть устойчив — изменить его значит сломать каждую ссылку, уже указывающую на страницу, — и должен быть однозначен при записи от руки, что исключает пробелы, прописные буквы, которые читатель может воспроизвести, а может и нет, и пунктуацию, что-то значащую для оболочки или разборщика Markdown.

Как снимаются диакритики

Большинство латинских диакритик снимает платформа, а не таблица. Unicode определяет é как разложимую на простую e и следующее за ней комбинирующее акутовое ударение, поэтому нормализация к этой разложенной форме и последующее отбрасывание каждого комбинирующего знака оставляет простую букву. Та же операция справляется с ñ, ç, ő и ещё несколькими сотнями, и она не может устареть, поскольку опирается на данные Unicode, которые браузер уже несёт.

Она справляется не со всем, и об этом пробеле стоит знать. Буква, чей знак — черта, перечёркивающая глиф, а не значок над ним (ø, ł, đ, ħ, ŧ), — это единый неделимый символ вовсе без разложения, так что снятие знаков оставляет его ровно таким, каким он был. То же и с лигатурой: ß, æ и œ обозначают каждая последовательность звуков, а не букву с украшением. Всем им нужно явное написание, и без него они просто исчезли бы из slug.

Почему настройка языка меняет ответ

Единственно верной латинизации ü не существует. Немецкий пишет её ue ещё с тех пор, как умлаута не было, — две точки начались как маленькая надстрочная e, — поэтому Müller правильно будет mueller, и немецкому читателю muller покажется ошибкой. Французский, испанский и португальский обходятся со своими диакритиками как со значками над буквой, которая в остальном остаётся собой, поэтому crème brûlée правильно даёт creme-brulee, а написание cruemme было бы бессмыслицей.

Северные языки расходятся между собой ровно так же. Датский и норвежский удваивают гласную, следуя старому написанию, которое буква заменила; шведский — нет:

  • Немецкий — ä становится ae, ö становится oe, ü становится ue, ß становится ss. München даёт muenchen.
  • Датский и норвежский — æ становится ae, ø становится oe, å становится aa. Ålborg даёт aalborg.
  • Шведский — ä становится a, ö становится o, å становится a. Ålborg даёт alborg.
  • Общий — всякий знак отбрасывается, базовая буква сохраняется. Ålborg даёт alborg, München даёт munchen.

Это не соперничающие приближения к одному ответу; это четыре разных правильных ответа на четыре разных вопроса. По умолчанию может стоять лишь один, поэтому настройка на виду, и инструмент называет соглашение, которое дало то, что вы видите. Одна буква везде одинакова: ß — лигатура, а не диакритика, отбросить её значило бы стереть звук, и здесь она ss при любой настройке.

Письменности, которым нужна таблица

Ничто в браузере не латинизирует кириллицу, греческий, иврит и арабский, поэтому каждая из них — таблица, написанная вручную по опубликованному стандарту. Две выходят хорошо, потому что записывают свои гласные:

  • Кириллица следует BGN/PCGN — латинизации англоязычных карт и паспортов: ж это zh, ч это ch, щ это shch, х это kh. Москва даёт moskva, а Чехов даёт chekhov.
  • Греческий следует ELOT 743 вместе с диграфами, которые тот определяет: ου это ou, а не oy, и ευ это ev. Αθήνα даёт athina, а Ευρώπη даёт evropi.

ISO 9 — другой известный кириллический стандарт, и здесь он намеренно не используется. Он обратим, в этом весь его смысл, но добивается этого диакритиками: ж там ž. В slug нет места для гачека, так что буква тут же сплющилась бы в z — и Жуков с Зуковым дали бы один и тот же slug. Диграф BGN такое сплющивание переживает.

Одна деталь кириллической таблицы легко упускается и заслуживает быть названной. ё и й выглядят как буквы с диакритикой, и Unicode именно так их и раскладывает, но знак здесь — то, что делает их другими буквами, а не украшение на той же самой. Снять знаки до обращения к таблице — верный порядок для всякой другой письменности здесь — значит тихо превратить Ёлку в elka, а Андрея в andrei.

Иврит и арабский, и что они теряют

Обе письменности записывают согласные, а большинство гласных оставляют точкам, которых обычный текст не несёт. Это не проблема кодировки, которую инструмент решил бы таблицей получше: сведений просто нет в тексте. «מאמר» — четыре буквы, мем-алеф-мем-реш, и чтение maamar исходит от читателя, уже знающего слово. Побуквенно из него может выйти только mamr.

Что можно сделать — сделано. Там, где буква служит и знаком гласного, используется положение, потому что это единственный сигнал, который оставляет неогласованный текст:

  • ו и י — согласные в начале слова и буквы-гласные внутри него, и именно это превращает שלום в shlom, а не в shlvm.
  • Удвоенные וו или יי — согласный в обоих местах: этим удвоением иврит и различает два чтения.
  • ב‎, כ и פ — взрывные в начале слова и щелевые внутри. Дагеш, отмечающий разницу, — это огласовка, так что остаётся только положение.
  • Буква с последующим герешем — звук, для которого у алфавита нет буквы: ג׳ это j, צ׳ это ch, ז׳ это zh. Пренебречь им значило бы превратить ג׳אז в другое слово.
  • Арабские эмфатические согласные сливаются со своими простыми парами, потому что в ASCII некуда поставить различающую их точку снизу. صابر и سابر дают один и тот же slug.

Результат читаем и узнаваем — и это не то написание, которое кто-нибудь назвал бы правильным. Инструмент говорит об этом при каждом ивритском или арабском результате, вместо того чтобы выдавать ответ с потерями за законченный, и указывает на форму ниже, которая не теряет ровно ничего.

Путь в Unicode, которому транслитерация не нужна

Путь URL не ограничен ASCII. RFC 3987 определяет IRI — идентификатор, который может содержать любой символ Unicode, — а правило передачи его по сети состоит в том, чтобы закодировать байты UTF-8 процентными последовательностями. Всякий браузер делает это два десятилетия, и потому Википедия отдаёт свои ивритские и русские заголовки статей под их собственными именами, а адресная строка показывает их читаемо.

Поэтому второй вывод здесь — заголовок с приведённой в порядок пунктуацией и пробелами и ничем больше не тронутый, а третий — то, как это выглядит в сети на самом деле. Это один и тот же путь: читаемая форма — то, что показывает браузер и что копирует человек, а закодированная — то, что записывает сервер.

Что выбрать — настоящее решение, а не формальность. Форма Unicode не теряет ничего, читается правильно для всякого, кто знает язык, и именно её покажет поисковая система. Транслитерированная форма переживает вставку туда, где кодировки портятся, помещается в системы, предполагающие пути в ASCII, и её можно прочесть по телефону. Для иврита и арабского в особенности форма Unicode обычно лучший ответ — как раз потому, что транслитерация не в силах вернуть гласные.

Арабский заголовок, проведённый до конца

Всё сказанное выше сходится в одном обычном заголовке, и вот один такой, проведённый от начала до конца. تعلم البرمجة значит «учиться программировать» — два слова, без знаков препинания и без огласовок, а именно так арабский и пишут везде, кроме учебника, словаря и священного текста.

Возвращаются три формы. Slug — это tlm-albrmjh; путь в Unicode — это تعلم-البرمجة, то есть сам заголовок, в котором разделитель занял место пробела; а в сети этот же путь выглядит как %D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9, те же два слова в байтах UTF-8. Потеряла что-то только первая из трёх, и потеряла в каждом из двух слов:

  • Слово تعلم читается taallum. Входят четыре буквы, выходят три: у ع нет буквы в латинском алфавите, поэтому она отбрасывается, а не записывается выдуманным знаком, а короткие гласные, которые слышит читатель, никогда и не были написаны.
  • Слово البرمجة читается al-barmaja. Определённый артикль ال приходит как al, а конечная та марбута ة записывается как h — по букве, чью форму она заимствует, а не как слышимое a: гласную эта письменность и опускает.
  • Прочитайте tlm-albrmjh обратно — и ничто в нём не скажет, какие гласные стояли между согласными. taallum — это то, чем слово является, tlm — это то, чем являются буквы, и перейти от одного к другому может только тот, кто слово уже знает.

Потеря не ограничивается чтением. عمر, имя Омар, возвращается как mr — и так же возвращается مر, совсем другое слово, потому что ع, которая их различала, исчезла. Два разных заголовка могут поэтому сойтись на одном slug, и режим списка помечает это как совпадение, а не нумерует молча; форма пути в Unicode у каждого из них держит их порознь, потому что она держит всё.

Совпадения, и почему они не разрешаются за вас

Построение slug снимает пунктуацию, поэтому заголовки, различающиеся только ею, перестают различаться вовсе. «Наше руководство по CSS» и «Наше руководство по CSS!» — это две записи и один slug. В режиме списка каждое такое столкновение отмечается строкой, с которой оно совпало, потому что это и есть та неполадка, которую система управления содержимым прячет: она молча добавляет суффикс, публикует, и ожидаемый вами адрес принадлежит другой записи.

Суффикс доступен как переключатель и даёт стиль WordPress и Django — nashe-rukovodstvo-po-css, nashe-rukovodstvo-po-css-2 — на случай, когда список нужно вставить куда-то как есть. По умолчанию он выключен, потому что совпадение обычно проблема содержания, а не именования, и совпадение остаётся отмеченным даже при включённом переключателе: включить его — не значит что-либо спрятать.

Длина, и обрезка в нужном месте

Ограничение длины режет по границе разделителя и никогда внутри слова. Обрезка посреди слова даёт не столько более короткий slug, сколько другой — introduction-to-crypt это не более опрятный introduction-to-cryptography, — а половина слова есть слово, значащее иное. Если единственное слово длиннее предела, границы для реза нет, и оно возвращается целиком, а не рассечённым.

Универсально верного предела не существует. Поисковые системы показывают примерно первые шестьдесят-семьдесят символов адреса, а старые системы иногда ограничивают сегмент пути, но ни на каком конкретном числе ничего не ломается. Оставленное пустым поле оставляет slug таким длинным, какого требует заголовок.

Частые вопросы

Какие символы безопасны в slug для URL?
Строчные буквы ASCII, цифры и один разделитель сработают везде без исключений. Дефис — привычный разделитель; подчёркивание работает так же, но хуже видно под подчёркнутой ссылкой. Пробелы, прописные буквы и пунктуация технически кодируются и все на практике доставляют хлопоты, поэтому slug их убирает.
Дефис или подчёркивание?
Дефис, по двум причинам, переживающим моду. Его использует всякая крупная платформа, а значит, его ждут и читатели, и другие инструменты, и он исчезает под подчёркиванием, которое несёт большинство ссылок, — чего о подчёркивании не скажешь. Выбор предлагается здесь потому, что у существующих систем есть существующие соглашения, и единообразие внутри одного сайта важнее любого из двух ответов.
Почему заголовок на иврите или арабском теряет гласные?
Потому что их и не писали. Обе письменности отмечают большинство гласных точками, которые обычный текст опускает, поэтому побуквенное чтение — всё, что любой инструмент может выдать без огласовочного движка, угадывающего задуманное слово. Этот транслитерирует то, что действительно есть, сообщает об этом рядом с результатом и предлагает форму пути в Unicode, сохраняющую заголовок ровно таким, каким его набрали.
Почему мой арабский заголовок теряет целые буквы, а не только гласные?
Потому что двум арабским согласным не во что превратиться в латинице. ع и ء — это звуки, которых английский не пишет, и выдумать для них знак было бы хуже, чем их потерять, поэтому они отбрасываются: تعلم возвращается как tlm, три буквы из четырёх. Гласные — потеря более известная, но не единственная. У формы пути в Unicode рядом со slug нет ни той проблемы, ни другой, потому что она ничего не транслитерирует.
Может ли URL содержать иврит, арабский или китайский напрямую?
Да. Путь может нести любой символ Unicode; в сети он кодируется процентами как UTF-8, а браузер показывает его читаемо. Именно так Википедия отдаёт названия статей на всех языках, которые охватывает. Этот инструмент показывает и читаемую форму, и закодированную, поскольку вторая — то, что появляется в журналах сервера и в аналитике.
Почему Müller то mueller, то muller?
Потому что верно и то и другое, в разных языках. Немецкий выписывает умлаут полностью — две точки родились как маленькая надстрочная e, — тогда как французский и испанский обходятся со своими диакритиками как со значками над буквой, которая в остальном остаётся собой. Настройка языка выбирает соглашение, и инструмент сообщает, какое именно он применил.
Почему два моих заголовка дают один и тот же slug?
Потому что построение slug убирает пунктуацию и регистр, а это часто единственное, что разделяет два заголовка. Режим списка отмечает каждое совпадение строкой, с которой оно столкнулось. Можно включить суффикс -2 в духе WordPress, но лежащий глубже вопрос — должны ли две записи действительно носить почти одно имя — стоит решить первым.
Отправляется ли что-нибудь из набранного на сервер?
Нет. Все преобразования выполняются в вашем браузере; ничто не загружается и не записывается, и всё работает без сетевого соединения.

Похожие инструменты