מחולל slug לכתובות

הופך כותרת ל-slug לכתובת, עם תעתיק מעברית, ערבית, קירילית ויוונית, לצד נתיב ביוניקוד ובדיקת התנגשויות ברשימות.

Slug
creme-brulee-grusse-aus-munchen
נתיב ביוניקוד — בלי תעתיק, בלי אובדן
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 שכתובת יכולה לשאת: אותיות קטנות, בלי פיסוק, מילים מחוברות במפריד שאתם בוחרים. דיאקריטים לטיניים מוסרים, ועברית, ערבית, קירילית ויוונית מתועתקות לאותיות לטיניות.

לצד ה-slug יושבת אותה כותרת בדיוק, שמורה בכתב שלה עצמה. גם הצורה הזאת היא נתיב חוקי, ולכתבים שמאבדים הכי הרבה בתעתיק היא לעיתים קרובות התשובה הטובה יותר — ולכן שתיהן מופקות מכותרת אחת במקום שהכלי יבחר בשבילכם.

למה משמש slug

‏slug הוא החלק הקריא לאדם בכתובת: הקטע שאחרי הלוכסן האחרון שנותן לעמוד שם במקום מספר. הוא קיים מפני שנתיב שנקרא כמילים שורד הדבקה להודעה, הדפסה על שקופית, והקראה בקול בטלפון, ומזהה מספרי לא עושה אף אחד מאלה.

זו גם הסיבה שהצורה כל כך מוגבלת. ‏slug צריך להיות יציב — שינוי שלו שובר כל קישור שכבר מצביע על העמוד — וצריך להיות חד-משמעי כשכותבים אותו ביד, מה שפוסל רווחים, אותיות גדולות שקורא עשוי לשחזר או לא, ופיסוק שאומר משהו למעטפת או למפרש Markdown.

איך יורדים הדיאקריטים

את רוב הדיאקריטים הלטיניים מסירה הפלטפורמה ולא טבלה. יוניקוד מגדיר את é כניתנת לפירוק ל-e פשוטה ואחריה סימן משולב של אקוט, ולכן נרמול לצורה המפורקת ההיא והשלכה של כל סימן משולב מותירים מאחור את האות הפשוטה. אותה פעולה מטפלת ב-ñ, ב-ç, ב-ő ובעוד כמה מאות, והיא לא יכולה להתיישן, מפני שהיא משתמשת בנתוני יוניקוד שהדפדפן כבר נושא.

היא לא מטפלת בכול, וכדאי להכיר את הפער. אות שהסימן שלה הוא קו חוצה את הצורה ולא סימן מעליה — ‏ø, ‏ł, ‏đ, ‏ħ, ‏ŧ — היא תו יחיד ובלתי מתחלק בלי שום פירוק, ולכן הסרת סימנים משאירה אותו בדיוק כפי שהיה. וכך גם ליגטורה: ‏ß, ‏æ ו-œ מייצגת כל אחת רצף צלילים, לא אות ועוד קישוט. כל אלה זקוקות לכתיב מפורש, ובלעדיו היו פשוט נעלמות מה-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 שורד את ההשתטחות.

פרט אחד בטבלה הקירילית קל לטעות בו וכדאי לומר אותו. ‏ё ו-й נראות כמו אותיות עם דיאקריט, ויוניקוד אכן מפרק אותן כך, אבל הסימן הוא מה שעושה אותן אותיות אחרות ולא קישוט על אותה אות. הסרת סימנים לפני פנייה לטבלה — הסדר הנכון לכל כתב אחר כאן — הופכת בשקט את Ёлка ל-elka ואת Андрей ל-andrei.

עברית וערבית, ומה שהן מאבדות

שני הכתבים כותבים עיצורים ומשאירים את רוב התנועות לנקודות שטקסט רגיל אינו נושא. זו אינה בעיית קידוד שהכלי הזה היה יכול לפתור בטבלה טובה יותר: המידע אינו בטקסט. ‏«מאמר» היא ארבע אותיות, מם-אלף-מם-ריש, והקריאה maamar מגיעה מקורא שכבר יודע את המילה. אות אחרי אות היא יכולה להיות רק mamr.

מה שאפשר לעשות נעשה. במקום שאות משמשת גם כסימן תנועה נעשה שימוש במיקום, מפני שזה האות היחיד שטקסט לא מנוקד מותיר:

  • ‏ו ו-י הן עיצורים בתחילת מילה ואמות קריאה בתוכה, וזה מה שהופך את «שלום» ל-shlom ולא ל-shlvm.
  • ‏וו או יי כפולות הן העיצור בשני המקומות — ההכפלה הזאת היא בדיוק הדרך שבה העברית מבדילה בין שתי הקריאות.
  • ‏ב, ‏כ ו-פ הן פוצץ בתחילת מילה וחוכך בתוכה. הדגש שמסמן את ההבדל הוא סימן ניקוד, ולכן המיקום הוא כל מה שנשאר.
  • אות שאחריה גרש היא הצליל שלאלפבית אין לו אות: ‏ג׳ היא j, ‏צ׳ היא ch, ‏ז׳ היא zh. התעלמות ממנו הייתה הופכת את «ג׳אז» למילה אחרת.
  • עיצורים נחציים בערבית מתמוטטים אל מקביליהם הפשוטים, מפני של-ASCII אין לאן לשים את הנקודה שמתחת שמבדילה ביניהם. ‏«صابر» ו-«سابر» מפיקות אותו slug.

התוצאה קריאה וניתנת לזיהוי, והיא אינה כתיב שמישהו היה קורא לו נכון. הכלי אומר זאת על כל תוצאה בעברית או בערבית במקום להציג תשובה מאבדת ככזו שהושלמה — ומצביע על הצורה שלמטה, שאינה מאבדת דבר.

נתיב היוניקוד, שאינו זקוק לתעתיק

נתיב של כתובת אינו מוגבל ל-ASCII. תקן RFC 3987 מגדיר את ה-IRI — מזהה שיכול להכיל כל תו יוניקוד — והכלל להעברתו על החוט הוא לקודד את בייטי ה-UTF-8 כמילוטי אחוזים. כל דפדפן עושה זאת זה שני עשורים, ולכן ויקיפדיה מגישה את כותרות המאמרים שלה בעברית וברוסית תחת שמן שלהן ושורת הכתובת מציגה אותן קריאות.

ולכן הפלט השני כאן הוא הכותרת שהפיסוק והרווחים שלה נוקו ושום דבר אחר לא נגע בו, והשלישי הוא איך זה נראה בפועל על החוט. שניהם אותו נתיב: הקריא הוא מה שדפדפן מציג ומה שאדם מעתיק, והמקודד הוא מה שהשרת רושם ביומן.

במה להשתמש היא החלטה אמיתית ולא פורמליות. צורת היוניקוד אינה מאבדת דבר, נקראת נכון לכל מי שדובר את השפה, והיא מה שמנוע חיפוש יציג. הצורה המתועתקת שורדת הדבקה למקומות שמשבשים קידודים, מתאימה למערכות שמניחות נתיבי ASCII, ואפשר להקריא אותה בטלפון. לעברית ולערבית בפרט צורת היוניקוד היא בדרך כלל התשובה הטובה יותר, דווקא מפני שהתעתיק אינו יכול לשחזר את התנועות.

התנגשויות, ולמה הן לא נפתרות בשבילכם

הפקת slug מסירה פיסוק, ולכן כותרות שנבדלות רק בפיסוק חדלות להיבדל כלל. ‏«המדריך שלנו ל-CSS» ו-«המדריך שלנו ל-CSS!» הן שני פוסטים ו-slug אחד. במצב רשימה כל התנגשות כזו מסומנת עם השורה שאיתה היא מתנגשת, מפני שזו התקלה שמערכת ניהול תוכן מסתירה: היא מוסיפה סיומת בשקט, מפרסמת, והכתובת שציפיתם לה שייכת לפוסט האחר.

הסיומת זמינה כמתג ומפיקה את הסגנון של WordPress ושל Django — ‏our-guide-to-css, ‏our-guide-to-css-2 — למקרה שרשימה נועדה להידבק למקום כלשהו כמות שהיא. היא כבויה כברירת מחדל מפני שהתנגשות היא בדרך כלל בעיית תוכן ולא בעיית שמות, וההתנגשות נשארת מסומנת גם כשהמתג דלוק, כך שהדלקתו אינה מסתירה דבר.

אורך, וחיתוך במקום הנכון

מגבלת אורך חותכת על גבול מפריד, לעולם לא בתוך מילה. חיתוך באמצע מילה אינו מפיק slug קצר יותר אלא slug אחר — ‏introduction-to-crypt אינו introduction-to-cryptography מסודר יותר — וחצי מילה היא מילה שמשמעה משהו אחר. אם מילה יחידה ארוכה מהמגבלה אין גבול לחתוך עליו, והיא מוחזרת בשלמותה במקום להיפרס.

אין מגבלה נכונה אוניברסלית. מנועי חיפוש מציגים בערך את שישים עד שבעים התווים הראשונים של כתובת, ומערכות ישנות לפעמים חוסמות מקטע נתיב, אבל שום דבר לא נשבר במספר מסוים. השארת השדה ריק משאירה את ה-slug ארוך כפי שהכותרת דורשת.

שאלות נפוצות

אילו תווים בטוחים ב-slug של כתובת?
אותיות ASCII קטנות, ספרות ומפריד יחיד יעבדו בכל מקום בלי יוצא מן הכלל. מקף הוא המפריד המקובל; קו תחתון עובד באופן זהה אבל קשה יותר לראות אותו מתחת לקישור שמסומן בקו תחתון. רווחים, אותיות גדולות ופיסוק כולם ניתנים לקידוד מבחינה טכנית וכולם גורמים צרות בפועל, ולכן slug מסיר אותם.
מקף או קו תחתון?
מקף, משתי סיבות שמאריכות ימים יותר מהאופנה. זה מה שכל פלטפורמה גדולה משתמשת בו, ולכן זה מה שקוראים וכלים אחרים מצפים לו, והוא נעלם מתחת לקו התחתון שרוב הקישורים נושאים, בעוד קו תחתון לא. הבחירה מוצעת כאן מפני שלמערכות קיימות יש מוסכמות קיימות, ועקביות בתוך אתר אחד חשובה יותר מכל אחת מהתשובות.
למה הכותרת שלי בעברית או בערבית מאבדת את התנועות?
מפני שהן מעולם לא נכתבו. שני הכתבים מסמנים את רוב התנועות בנקודות שטקסט רגיל משמיט, ולכן קריאה אות-אחר-אות היא כל מה שכלי יכול להפיק בלי מנוע ניקוד שינחש איזו מילה נתכוונה. הכלי הזה מתעתק את מה שבאמת שם, אומר זאת על התוצאה, ומציע את צורת נתיב היוניקוד ששומרת את הכותרת בדיוק כפי שהוקלדה.
האם כתובת יכולה להכיל עברית, ערבית או סינית ישירות?
כן. נתיב יכול להחזיק כל תו יוניקוד; הוא מקודד באחוזים כ-UTF-8 על החוט ומוצג קריא בידי הדפדפן. כך ויקיפדיה מגישה כותרות מאמרים בכל שפה שהיא מכסה. הכלי הזה מציג גם את הצורה הקריאה וגם את המקודדת, מפני שהשנייה היא מה שמופיע ביומני שרת ובאנליטיקה.
למה Müller הוא לפעמים mueller ולפעמים muller?
מפני ששניהם נכונים, בשפות שונות. הגרמנית מאייתת את האומלאוט במלואו — שתי הנקודות התחילו את חייהן כ-e קטנה מעל — בעוד הצרפתית והספרדית מתייחסות לדיאקריטים שלהן כאל סימנים על אות שהיא בלאו הכי היא עצמה. בורר השפה בוחר מוסכמה, והכלי אומר לכם איזו הוא החיל.
למה שתי כותרות שלי מפיקות אותו slug?
מפני שהפקת slug מסירה פיסוק ורישיות, שהם לעיתים קרובות הדבר היחיד שמפריד בין שתי כותרות. מצב הרשימה מסמן כל התנגשות עם השורה שאיתה היא מתנגשת. אפשר להדליק את סיומת ה-2- בסגנון WordPress, אבל כדאי קודם לענות על השאלה שמתחת — האם באמת ראוי ששני פוסטים יישאו כמעט אותו שם.
האם משהו שאני מקליד נשלח לשרת?
לא. כל טרנספורמציה רצה בדפדפן שלכם; שום דבר אינו מועלה או נרשם, וזה עובד בלי חיבור רשת.