Кириличні заголовки постів у MangoBlog
З переїздом на Mango у нас відразу виникла проблема: при створенні токенів (імен) для URL постів на базі заголовку видалялись кириличні символи. Це відбувалось тому, що блоґ намагався зробити безпечні посилання, а в таких знаходилося місце тільки літерам латинки, цифрам та дефісам.
Наприклад, спробувавши створити такий пост:
Ми отримували не дуже гарне посилання на цей пост:
Найбільш серйозною проблемою була втрата унікальності URL'ів, коли "Мій пост про MySQL" мав би майже таке саме посилання, що й "Пост не тільки про MySQL". Майже, бо блоґ додав би якесь випадкове число для запобігання співпадінь.
Почухавши потилицю, я вирішив виправити це діло. Півгодини копирсання в коді дали зрозуміти, що найбільш безболісним буде шлях транслітерації заголовку до його "чистки".
Пошуки привели мене до службової компоненти Utilities.cfc (див. /components/). Серед її методів знайшовся передбачуваний regex методу makeCleanString():
<cfset cleanedString = rereplace(cleanedString, "[^a-z0-9]", "-", "all") />
<cfset cleanedString = rereplace(cleanedString, "-{2,}", "-", "all") />
<cfset cleanedString = rereplace(cleanedString, "(^-|-$)", "", "all") />
Не хотілось особливо влізати в працюючий код, тому довелось зробити своєрідного костиля -- новий метод transLitString(), котрий підміняє підходящі літери кирилиці на англійські відповідники згідно простої мапи замін, що міститься в самому ж методі. Виклик його вставлено на початку makeCleanString()
<!--- Code provided by Seb Duggan, thank you! --->
<cfset var s = this.transLitString(lcase(arguments.stringToClean)) />
<cfset var i = 0 />
<cfset var c = "" />
<cfset var cleanedString = "" />
Код самої компоненти:
<cffunction name="transLitString" output="false" hint="Transliterates Cyr string to Latin" access="public" returntype="string">
<cfargument name="stringToTrans" type="string" required="true">
<cfset var tranString = "" />
<cfset var i = 0 />
<cfset var c = "" />
<cfset var transMap = StructNew() />
<cfscript>
transMap["а"] = "a";
transMap["б"] = "b";
transMap["в"] = "v";
transMap["г"] = "g";
transMap["ґ"] = "g";
transMap["д"] = "d";
transMap["е"] = "e";
transMap["є"] = "ye";
transMap["ж"] = "zh";
transMap["з"] = "z";
transMap["и"] = "y";
transMap["й"] = "y";
transMap["і"] = "i";
transMap["ї"] = "yi";
transMap["к"] = "k";
transMap["л"] = "l";
transMap["м"] = "m";
transMap["н"] = "n";
transMap["о"] = "o";
transMap["п"] = "p";
transMap["р"] = "r";
transMap["с"] = "s";
transMap["т"] = "t";
transMap["у"] = "u";
transMap["ф"] = "f";
transMap["х"] = "h";
transMap["ц"] = "ts";
transMap["ч"] = "ch";
transMap["ш"] = "sh";
transMap["щ"] = "sch";
transMap["э"] = "e";
transMap["ь"] = "";
transMap["ы"] = "y";
transMap["ъ"] = "";
transMap["ю"] = "yu";
transMap["я"] = "ya";
</cfscript>
<cfloop from="1" to="#len(arguments.stringToTrans)#" index="i">
<cfset c = mid(arguments.stringToTrans,i,1) />
<cfif StructKeyExists(transMap, c)>
<cfset tranString = tranString & transMap[c] />
<cfelse>
<cfset tranString = tranString & c />
</cfif>
</cfloop>
<cfreturn tranString />
</cffunction>
Ось як виглядає наш пост після підміни компоненти:
Важлива примітка. На деяких інсталяціях ColdFusion можуть виникнути проблеми з розпізнаванням символів через помилки в обробці UTF-8, для вирішення проблеми достатньо вставити на початку компоненти директиву:
<cfprocessingdirective pageencoding="utf-8">
Пишіть рідною мовою про ColdFusion на здоров'я :)