Предпоставка на темата
Има три различни аспекта в многоезичен сайт:
- превод на интерфейс
- съдържание
- URL маршрутизиране
Въпреки че всички те са свързани помежду си по различни начини, от гледна точка на CMS те се управляват с помощта на различни елементи на потребителския интерфейс и се съхраняват по различен начин. Изглежда сте уверени в изпълнението и разбирането на първите две. Въпросът беше за последния аспект - „Превод на URL адрес? Трябва ли да направим това или не? и по какъв начин?“
От какво може да бъде направен URL адресът?
Много важно нещо е, не се захващайте с IDN . Вместо това предпочитайте транслитерация (също:транскрипция и романизация). Въпреки че на пръв поглед IDN изглежда жизнеспособна опция за международни URL адреси, тя всъщност не работи както се рекламира по две причини:
- някои браузъри ще променят символите, различни от ASCII, като
'ч'
или'ž'
в'%D1%87'
и'%C5%BE'
- ако потребителят има персонализирани теми, е много вероятно шрифтът на темата да няма символи за тези букви.
Всъщност се опитах да подходя към IDN преди няколко години в проект, базиран на Yii (ужасна рамка, IMHO). Срещнах и двата гореспоменати проблема, преди да изстържем това решение. Освен това подозирам, че може да е вектор на атака.
Налични опции ... както ги виждам.
По принцип имате два избора, които могат да се абстрахират като:
-
http://site.tld/[:query]
:където[:query]
определя избора както на език, така и на съдържание -
http://site.tld/[:language]/[:query]
:където[:language]
част от URL дефинира избора на език и[:query]
се използва само за идентифициране на съдържанието
Заявката е Α и Ω ..
Да приемем, че изберете http://site.tld/[:query]
.
В този случай имате един основен източник на език:съдържанието на [:query]
сегмент; и два допълнителни източника:
- стойност
$_COOKIE['lang']
за този конкретен браузър - списък с езици в заглавката на HTTP Accept-Language
Първо, трябва да съпоставите заявката с един от дефинираните модели за маршрутизиране (ако вашият избор е Laravel, тогава прочетете тук ). При успешно съвпадение на шаблона трябва да намерите езика.
Ще трябва да преминете през всички сегменти на шаблона. Намерете потенциалните преводи за всички тези сегменти и определете кой език е бил използван. Двата допълнителни източника (бисквитка и заглавка) ще бъдат използвани за разрешаване на конфликти при маршрутизиране, когато (а не „ако“) възникнат.
Вземете например:http://site.tld/blog/novinka
.
Това е транслитерация на "блог, новинка"
, което на английски означава приблизително "blog", "latest"
.
Както вече можете да забележите, на руски "блог" ще се транслитерира като "блог". Което означава, че за първата част на [:query]
вие (в най-добрия случай ) ще завърши с ['en', 'ru']
списък с възможни езици. След това взимате следващия сегмент - "новинка". Това може да има само един език в списъка с възможности:['ru']
.
Когато списъкът има един елемент, успешно сте намерили езика.
Но ако се окажете с 2 (пример:руски и украински) или повече възможности .. или 0 възможности, според случая. Ще трябва да използвате бисквитка и/или заглавка, за да намерите правилната опция.
И ако всичко друго не успее, вие избирате езика по подразбиране на сайта.
Език като параметър
Алтернативата е да използвате URL, който може да бъде дефиниран като http://site.tld/[:language]/[:query]
. В този случай, когато превеждате заявка, не е необходимо да отгатвате езика, защото в този момент вече знаете кой да използвате.
Има и вторичен източник на език:стойността на бисквитката. Но тук няма смисъл да се забърквате със заглавката Accept-Language, защото не се занимавате с неизвестно количество възможни езици в случай на „студен старт“ (когато потребителят за първи път отвори сайта с персонализирана заявка).
Вместо това имате 3 прости, приоритетни опции:
- if
[:language]
сегментът е зададен, използвайте го - if
$_COOKIE['lang']
е зададен, използвайте го - използвайте език по подразбиране
Когато имате езика, просто се опитвате да преведете заявката и ако преводът не успее, използвайте „стойността по подразбиране“ за този конкретен сегмент (въз основа на резултатите от маршрутизирането).
Тук ли не е трета опция?
Да, технически можете да комбинирате и двата подхода, но това би усложнило процеса и би настанило само хора, които искат ръчно да променят URL адреса на http://site.tld/en/news
до http://site.tld/de/news
и очаквайте страницата с новини да се промени на немски.
Но дори и този случай вероятно може да бъде смекчен с помощта на стойност на бисквитки (която ще съдържа информация за предишния избор на език), за да се приложи с по-малко магия и надежда.
Кой подход да използвате?
Както може би вече се досещате, бих препоръчал http://site.tld/[:language]/[:query]
като по-разумния вариант.
Също така в ситуация с реална дума ще имате 3-та основна част в URL:"title". Както в името на продукта в онлайн магазина или заглавието на статия в новинарския сайт.
Пример:http://site.tld/en/news/article/121415/EU-as-global-reserve-currency
В този случай '/news/article/121415'
ще бъде заявката, а 'EU-as-global-reserve-currency'
е заглавие. Чисто за SEO цели.
Може ли да се направи в Laravel?
Донякъде, но не по подразбиране.
Не съм много запознат с него, но от това, което видях, Laravel използва прост механизъм за маршрутизиране, базиран на шаблони. За да внедрите многоезични URL адреси, вероятно ще трябва да разширите основни клас(ове) , тъй като многоезичното маршрутизиране се нуждае от достъп до различни форми на съхранение (база данни, кеш и/или конфигурационни файлове).
Препратен е. Какво сега?
В резултат на всичко ще получите две ценни части информация:текущ език и преведени сегменти от заявката. След това тези стойности могат да се използват за изпращане до класа(овете), които ще произведат резултата.
По принцип следният URL адрес:http://site.tld/ru/blog/novinka
(или версията без '/ru'
) се превръща в нещо като
$parameters = [
'language' => 'ru',
'classname' => 'blog',
'method' => 'latest',
];
Което просто използвате за изпращане:
$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );
.. или някаква негова вариация, в зависимост от конкретната реализация.