How do I specify that a page is in a certain language so search engines can understand?
Is it a meta tag I put at the top? If it is, do you know if most of the search engines use this to determine language?
I have converted 1 page of content in english to several different languages, and would like to include that information in the html/let the search engines know which language they are dealing with.
asked Jul 1, 2009 at 23:19
Quick google search gave me this: HTTP and meta for language. tl;dr
<html lang="en">
There are other ways of specifying. If you are using apache, you can use a file extension for apache to pull the correct version based on the user-agent’s given preferences. for example, name your index page index.html.en
, index.html.jp
, index.html.de
and so on…
answered Jul 1, 2009 at 23:24
Depending on your dtd:
HTML:
<html lang="en">
XHTML:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
If you are using a right to left language:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="he" lang="he" dir="rtl">
If using XHTML, you’ll want to specify both the xml:lang and lang attributes. The xml:lang attribute takes precedence over lang.
answered Jul 1, 2009 at 23:42
TresTres
5,5743 gold badges18 silver badges17 bronze badges
Check this page for a range of things you can do to try to get the search engine to pick up the right language.
How to Specify an HTML Web Document Language for good SEO
(In no particular order)
- right domain suffix
- hosted in right county
- AddHeading syntax (Apache)
<meta http-equiv="Content-Language" content="yourlanguage" />
<html lang="yourlanguage">
for xhtml<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="yourlanguage" lang="yourlanguage">
<p lang="yourlanguage">
<meta http-equiv="content-type" content= "text/html; yourcharset">
- And search engines to text pattern analysis too (prefix/suffix of words, n-grams analysis)
answered Jul 1, 2009 at 23:28
jitterjitter
53.3k11 gold badges110 silver badges124 bronze badges
Intended audience: HTML coders, script developers, CSS coders, and anyone who needs guidance on how to declare and use language information in HTML. It is assumed that you have a basic familiarity with HTML and CSS.
This tutorial gathers together and organizes pointers to articles that, taken together, help you understand the essential aspects of how to work with language information when authoring HTML and CSS.
In a nutshell
Always add a lang
attribute to the html
tag to set the default language of your page.
<html lang="en">
If this is XHTML 1.x or an HTML5 polyglot document served as XML, you should also use the xml:lang
attribute (with the same value). If your page is only served as XML, just use the xml:lang
attribute.
Do not use the meta
element with http-equiv
set to Content-Language
.
Choose tags from the IANA Subtag Registry, and follow the syntax rules in BCP 47 when using more than just a language subtag. Keep your language tags as short as possible.
Use the :lang
property in CSS to apply styles dependent on the language of your content.
Why declare language?
This part of the tutorial sets the motivation for reading the remainder. If you are in a hurry and just want to know what to do, without the theory, start reading from the section How to declare the language of a page or element.
Browsers and other applications can use information about the language of content to deliver to users the most appropriate information, or to present information to users in the most appropriate way. The more content is tagged and tagged correctly, the more useful and pervasive such applications will become.
Why use the language attribute? includes examples of how language information can be useful.
How to declare the language of a page or element
You should set the language of the text in your page using language attributes. Unfortunately, there is more than one attribute involved in some formats, and a few other things to clarify. This section discusses the various options: those you should use, and those you should avoid (and why).
Declaring language in HTML provides a summary of how to declare language using attributes.
HTTP headers, meta elements and language information describes how language metadata differs from the actual language of the text, and discusses Content-Language as used in HTTP headers and meta elements.
Working with language tags
This section looks at how to choose and create language tags, ie. the values used for language attributes.
To be sure that all user agents recognize which language you mean, you need to follow a standard approach when providing language values. You may also need to consider how to refer to dialectal differences in a standard way, eg. the difference between US English and British English, which diverge significantly in terms of spelling and pronunciation.
Language tags in HTML and XML describes the syntax of language tags using the specification BCP 47.
Choosing a Language Tag provides practical information about how to select the right subtags from the thousands available to represent the language you need.
Setting your browser’s language preferences
When your browser pulls a document from the Web, it sends an HTTP request to the server where the information is stored. With the request, the browser sends information about its language preference settings. These preferences can determine what content is sent back to you. Learn how to set or change these preferences.
Setting language preferences in a browser
Using language information to style your document
You often want to apply different styles to text in different languages (eg. font or line height information, or perhaps different emphasis styles, etc.) If you have used attributes to identify the language of your content, you can use some powerful selectors in CSS to automatically apply different styling to the content as the language changes. The following article explores the various options for doing so.
Styling using language attributes
Further reading
-
Getting started? Language on the Web
-
Authoring HTML & CSS
- Language
Вот пример кода
Кусок разметки
<nav class="site-nav">
<ul id="navigation">
<li data-menuanchor="about-us">
<a href="#about-us" data-lang="about_academy">Про академию</a>
</li>
<li data-menuanchor="what-we-offer">
<a href="#what-we-offer" data-lang="proposal">Что мы предлагаем</a>
</li>
<li data-menuanchor="your-benefits">
<a href="#your-benefits" data-lang="your_result">Что ты получишь</a>
</li>
<li data-menuanchor="our-blog">
<a href="#our-blog" data-lang="blog">Блог</a>
</li>
<li data-menuanchor="testimonials">
<a href="#testimonials" data-lang="feedback">Отзывы</a>
</li>
<li data-menuanchor="contacts">
<a href="#contacts" data-lang="contacts">Контакты</a>
</li>
<li class="language-switcher-wrapper">
<button class="language-switcher ua">UA</button>
</li>
</ul>
</nav>
data-lang — это то что нужно переводить
Сами данные лежат в двух файлах в папке translations
ru.json
{
"about_academy": "Про Академию",
"proposal": "Что мы предлагаем",
"your_result": "Что ты получишь",
"feedback": "Что говорят выпускники",
"blog": "Блог",
"contacts": "Контакты",
"our_mission_main": "Наша миссия"
}
ua.json
{
"about_academy": "Про Академію",
"proposal": "Що ми пропонуємо",
"your_result": "Що ти отримаєш",
"feedback": "Що кажуть випускники",
"blog": "Блог",
"contacts": "Контакти",
"our_mission_main": "Наша місія"
}
JS
(function($) {
function Translate() {
//initialization
this.init = function(attribute, lng) {
this.attribute = attribute;
this.lng = lng;
};
//translate
this.process = function() {
var _self = this;
var xrhFile = new XMLHttpRequest();
//load content data
xrhFile.open("GET", "./translations/"+this.lng+".json", false);
xrhFile.onreadystatechange = function () {
if(xrhFile.readyState === 4) {
if(xrhFile.status === 200 || xrhFile.status == 0) {
var LngObject = JSON.parse(xrhFile.responseText);
console.log(LngObject["name1"]);
var allDom = document.getElementsByTagName("*");
for(var i =0; i < allDom.length; i++){
var elem = allDom[i];
var key = elem.getAttribute(_self.attribute);
if(key != null) {
console.log(key);
elem.innerHTML = LngObject[key];
}
}
}
}
};
xrhFile.send();
};
}
// Change language
function loadNewLang(new_lang) {
var translate = new Translate();
var currentLng = new_lang;
var attributeName = 'data-lang';
translate.init(attributeName, currentLng);
translate.process();
}
loadNewLang('ua');
$('.language-switcher').on('click', function(e) {
e.preventDefault();
$('.preloader').removeAttr('style');
if($(this).hasClass('ru')) {
$(this).toggleClass('ru ua').text('UA');
loadNewLang('ua');
ln_preloader();
} else if ($(this).hasClass('ua')) {
$(this).toggleClass('ua ru').text('RU');
loadNewLang('ru');
ln_preloader();
}
});
})(jQuery);
работает это все из под сервера
Простой способ добавить несколько языков на сайт -3
JavaScript, Из песочницы, HTML
Рекомендация: подборка платных и бесплатных курсов Python — https://katalog-kursov.ru/
Введение
В рамках своего проекта я столкнулся с задачей сделать текущий сайт компании мультиязычным. Более точно: создать возможность быстро и просто перевести сайт на английский, польский, итальянский и т.д.
Поиск в интернете показал, что существующие варианты создания мультиязычного сайта крайне громоздки и неэффективны. Подключать сторонние библиотеки зачастую проблемно, а советы по написанию своего решения связаны с большим объёмом однотипной работы.
Написание альтернативного метода смены локали заняло у меня всего несколько часов, а поддержание семантического единства и вовсе сводит к минимуму изменения при последующем добавлении новых страниц.
Исходные файлы примера сайта с автоматическим переводом можно скачать на github
Существующие альтернативы
Когда задача только появилась в разработке, первым шагом, разумеется, стало исследование готовых решений и советов на форумах о том, как наиболее просто и правильно реализовать возможность смены локали. Самые популярные интернет ресурсы для создания мультиязычных сайтов предлагаю следующие решения:
- Создание дублирующих html блоков с текстом на разных языках, из которых только один оставляется активным для пользователя, а остальные прячутся (display: none).
Очевидным минусом такого способа является невероятно быстрое увеличение кода и мгновенная потеря читабельности и поддерживаемости кода. Кроме того, такое решение является уязвимым для ошибок в тексте и масштабируемости с точки зрения увеличения количества языков (далее локалей).
- Подключение стороннего сервиса машинного перевода (такого как google translate) с большим количеством встроенных языков и минимальными изменениями в исходном коде страницы.
Когда задача только появилась в task list мы использовали этот способ как самый очевидный и удобный, однако опыт работы с клиентами – носителями языка из соединённых штатов и Израиля показал, что машинный перевод часто допускает ошибки при смене локали, а пользователи сайтов крайне резко реагируют на подобные ошибки перевода. В конце концом стратегические партнеры настойчиво посоветовали сменить способ изменения локали, и от этого способа пришлось отказаться.
- Смена языка при помощи возможностей js или сторонних библиотек/фреймворков, таких как jQuery, основанных на поиске и прямом изменении DOM элементов.
Особенностью такого подхода является поиск огромного количества js селекторов, текст внутри которых необходимо заменить. Такой подход может хорошо работать для небольших проектов, однако при увеличении количества страниц пропорционально увеличивается количества функций замены текста, что ведет к потере эффективности в больших проектах.
Альтернативное решение
Основой подхода, который я предлагаю, как альтернативу существующим способам является, как ни странно не база, написанного мной js кода, которая является в целом тривиальной, а правило оформление селекторов, поддерживание которого позволяет гибко и просто настроить перевод любого количество страниц на любой язык без изменения кодовой базы и излишнего дублирования данных.
В изменении локали при альтернативном подходе выделяются три основных игрока:
- html страница с установленным правилом оформления селекторов блоков с текстом
- общий js сервис, основная задача которого состоит в замене textContet DOM элементов согласно правилу оформления селекторов
- JSON файл локали, содержащий в себе структуру с содержанием html блоков на всех языках, используемых при смене локали
Соблюдение правила оформления селекторов изменяемых элементов позволяет избавиться от необходимости менять js код сервиса смены локали, что является большим плюсом с точки зрения масштабируемости проекта.
Правило построения селекторов
Большинство методов смены локали страницы (среди приведенных альтернатив 1,3 и частично 2) предполагают необходимость каким-либо способом «пометить» изменяемый html блок, как правильно при помощи изменении поля class. Этот же механизм использует и альтернативный вариант.
Первым шагом оформления селекторов является разделение исходной страницы на функциональные блоки верхнего уровня. На странице нашей компании — это блоки:
Каждому блоку даем условное название, например,
-
Меню (menu)
-
Визитная карточка (home)
-
Пример работы сервиса (example)
-
Партнеры (clients)
-
Область применения сервиса (userfulBlock)
-
Примеры работы сервиса (examples)
-
Контакты и обратная связь (contacts)
Пример на сайте
После этого мы далее разбиваем каждый блок на более мелкие функциональные блоки, как это делается при применении библиотеки React.
Пример на сайте
Выделенным областям присваиваем свои имена и получаем структуру вида:
-
menu
-
home main, description, buttons
-
example statistics, headline, description, buttons
-
clients buttons
-
userfulBlock headline, userfulCards, elseBlock
-
examples headline, cards
-
contacts headline, description, contacts, form
Далее продолжаем эту процедуру пока не достигнем блоков, содержащих исходный текст.
В итоге получаем готовую структуру JSON файла локали, содержащий все необходимые тексты для изменения языка. Также, исходя из этого алгоритма определяется правило построения селекторов:
Каждый селектор начинается с ключевого слова locale и далее, согласно стилю dash case добавляются имена всех родительских блоков включая блок, содержащий исходный текст, например, описание примера в первой карточке будем иметь селектор locale-example-cards-description
Пример на сайте
Пример полученного файла json локали можно увидеть на github
Сервис смены локали
Сервис смены локали представляет собой модуль, содержащий функцию загрузки файла локали
loadLocale(defLang)
с необязательным параметром defLang – язык установленные после загрузки локали (язык по умолчанию), а также основную функцию изменения текущей локали
changeLocale(lang)
с указанием требуемого языка.
Функция загрузки локали
Функция загрузки локали использует стандартный XMLHttpRequest запрос за данными. Использование именного этого стандарта обусловлено желанием минимизировать количество зависимостей и простотой использования запроса. После получения файла локали в консоль выводится оповещение о получении данных, а также вызывается функция изменения локали на язык по умолчанию в случае, если этот язык был передан в функцию как необязательный параметр. Ознакомиться с кодом функции можно тут:
function loadLocale(defLang) {
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://localhost:3000/locale.json', true);
xhr.onreadystatechange = saveLocale.bind(this);
xhr.onerror = function () { console.log("no found page"); };
xhr.send();
function saveLocale() { if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
locale = JSON.parse(xhr.responseText);
console.log("locale loaded");
if(defLang) changeLocale(defLang);
} }
}
Функция изменения локали
Типы данных
Представляет собой рекурсивную функцию, основной задачей которой являет обход объекта, содержащий локаль страницы (используя DFS алгоритм). Использование рекурсии при построении функции позволяет закодировать алгоритм максимально просто и лаконично, однако слишком большая глубина рекурсии может привести к переполнению стека. Особенности обхода данной проблемы можно найти на одноименном форуме, либо же ознакомившись с соответствующими статьями на habr.com.
В основе работы рекурсивной функции заложена обработка 4 типов данных:
- поле содержащее строку исходного текста, используемого для добавления на страницу.
Например:"main": "Продающий квест из вашего видео"
- поле содержащее массив строк исходного текста, используемого для добавления на
страницу. Такое поле необходимо для создания списков, элементы которых могут менять
порядок. Например:"menu":["Home","Example","Clients","Info","Contacts"]
- Вложенная структура данных, содержащая свой набор полей, необходимая для построения
архитектуры страницы. Например:"home": { "main": "selling quest from your video", "description": "for social networks & sites", "buttons": ["try","order"] }
- Массив вложенных структур данных, с одинаковым набором используемых полей. Такие
массивы используются, когда появляются списки одинаковых блоков кода, например,
карточек участников команды, или портфолио или тарифов оказываемых услуг.
Например:"usefulCards": [ { "headline": "Marketers and agencies", "statistics": ["convers 26%", "retent 25%"], "button": "ORDER" }, { "headline": "Production studios and TV platforms", "statistics": ["convers 24%", "retent 33%"], "button": "ORDER" }, { "headline": "Conference creators", "statistics": ["convers 65%", "retent 15%"], "button": "ORDER" }, { "headline": "Bloggers and streamers", "statistics": ["convers 24%", "retent 33%"], "button": "ORDER" } ],
На сайте это может выглядеть так:
Пример на сайте
Функции обработки
Обработка типа данных с исходным текстом осуществляется отдельной функцией
function getText(key, object, name,startIndex)
Принимающей на вход название поля структуры с исходным текстом, текущий объект локали, содержащий текст, который нужно добавить и текущее имя селектора, необходимое для поиска DOM элемента.
function getText(key, object, name, startIndex) {
var elementKey=0;
if(startIndex) elementKey = startIndex;
for ( ; elementKey < document.getElementsByClassName(name + "-" + key).length; elementKey++)
if (!isNaN(elementKey)) document.getElementsByClassName(name + "-" + key)[elementKey].textContent = object[key];
}
Обработка массива строк с исходным текстом также осуществляется отдельной функцией
function getArrayText(key, object, name,startIndex)
Сигнатура и тело этой функции ничем не отличается от прошлой за исключением того, что элементам DOM присваиваются элементы из массива.
function getArrayText(key, object, name, startIndex) {
var elementKey=0;
if(startIndex) elementKey = startIndex;
for ( ; elementKey < document.getElementsByClassName(name + "-" + key).length; elementKey++)
if (!isNaN(elementKey)) document.getElementsByClassName(name + "-" + key)[elementKey].textContent = object[key][elementKey % object[key].length];
}
Основная рекурсивная функция замены текста занимается классификацией текущего поля локали в один 4 приведенных выше типов и соответствующей реакцией на полученный тип:
function changeText(name, object, startIndex) {
for (key in object)
if (Array.isArray(object[key]) && typeof object[key] != 'string' && typeof object[key][0] == 'string') getArrayText(key, object, name);
else if (typeof object[key] == "object" ){
if(isNaN(key)) changeText(name + "-" + key, object[key]);
else changeText(name, object[key],key);
}
else getText(key, object, name, startIndex);
}
На вход эта функция принимает текущую языковую локаль и корневой селектор (в данном случае “locale”). Далее при обнаружении вложенной структуры или массива структур функция будет рекурсивно вызывать саму себя, соответствующе изменяя входные параметры.
Основным плюсом альтернативного подхода является то, что описанный выше сервис не требует никаких функциональных изменений, и добавляется как js файл, использующий созданный вами файл локали.
Заключение
Суть описанного выше подхода заключается в зафиксированном правиле описания селекторов и построения файла локали. Благодаря этому появляется уникальная возможность перевода любых страниц из коробки и переиспользования уже переведенного материала.
Описанный выше алгоритм построения селекторов не является обязательным и критичным для работы сервиса. Сервис является гибким для расширения и добавления новых методов и алгоритмов, а также для построения имен селекторов и структуры json локали. Возможным плюсом будет являться сохранение локали в cookie браузера и изменение локали, в зависимости от местоположения пользователя сервиса.
Исходные файлы примера сайта с автоматическим переводом можно скачать на github.
While you can handle the request dynamically, you need to provide another method, and here’s why. According to Google if you care anything about SEO, you’ll want to Make sure the page language is obvious. You can do the hat trick on the fly and switch the language via language preferences, but you also need to provide a link to a page that is always in the other language if you expect to get any traffic in that language from search engines.
If this page dynamically detects the language, then whatever language Google sees when it crawls is the language it will make the page as.
http://www.example.com/
If the site contains a query string flag for another language the site is likely to be crawled in both languages IF there is a link to the second language somewhere on your site. These are good examples (a separate domain is the best option) for showing Google where a Spanish page would reside.
http://es.example.com - best for SEO
http://www.example.com/?lang=es
http://www.example.com/es/
In your PHP code you’re only catching the initial 2 digit code for the preferred language of the browser. Some people actually read in more than one language (basically anyone who’s not American). They might have those other languages in their preferred languages, so while someone from France may have fr
as their preferred language, they may also understand English (en
), so their browser accepted string might look something like this in Chrome:
fr,en-US;q=0.8,en;q=0.6
or this in IE:
fr-FR,en-US;q=0.5
This code will check to see if they’ve set the $_GET
flag for the language and override the automatic translation. I found this code, then modified it to work for my purposes because the site where it’s being used is European where most people speak multiple languages. For this code I’ve modified it here, so if their preferred language isn’t Spanish it will default to English. This would go into a file like lang.php
which would get included on every page.
<?php
$langs = array();
if (!empty($_GET['lang'])){
$tempLang = $_GET['lang'];
//Setup the switch for all of the possible languages.
switch($tempLang){
case 'es':
$pref='es';
break;
default:
//english
$pref='en';
}
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)s*(;s*qs*=s*(1|0.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])) {
// create a list like "en" => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') $val = 1;
$lParse = strtolower(preg_replace('!-.*$!','',$lang));
if(!isset($newLangs[$lParse])){
$newLangs[$lParse] = $val;
}
}
// sort list based on value
arsort($newLangs, SORT_NUMERIC);
}
//Set the preferred languages for the website (available translations)
$preferred = array('en','es');
//Check for overlap keeping the preference order
$intersect = array_values(array_intersect(array_keys($newLangs), $preferred));
//print_r($newLangs);
if(isset($intersect[0])){
//Set the first preference
$pref = $intersect[0];
if(preg_match('!^es!',$pref)){
$pref='es';
}
} else {
//default to english
$pref = 'en';
}
} else {
//default to english
$pref = 'en';
}
?>
On the page including lang.php
you would need to check the $pref
variable to show the proper translation for the language.
Javascript
You can do a redirect with Javascript to make the page load the other language using this same code, however search engines typically only look at Javascript for exploits and won’t follow the links in the Javascript. According to Google Webmaster’s Guidelines:
Use a text browser such as Lynx to examine your site, because most
search engine spiders see your site much as Lynx would. If fancy
features such as JavaScript, cookies, session IDs, frames, DHTML, or
Flash keep you from seeing all of your site in a text browser, then
search engine spiders may have trouble crawling your site.
You can do the change with a click using AJAX, however the URL where AJAX would listen would need to be passed the parameter and these are usually passed via $_GET
variables.
IP Look-up
Another method some people have tried is to check the IP address and reverse look-up the location to see where the country of origin is, then they’ll pick the national language. The problems with this are:
- People travel
- Some IP addresses are registered to owners in other countries (think corporate blocks) rather than the country where the user is browser.
- Some of the IP address listings are highly inaccurate.
Cookies
Not all users accept cookies and some corporate firewalls may even strip the cookies.
While you can handle the request dynamically, you need to provide another method, and here’s why. According to Google if you care anything about SEO, you’ll want to Make sure the page language is obvious. You can do the hat trick on the fly and switch the language via language preferences, but you also need to provide a link to a page that is always in the other language if you expect to get any traffic in that language from search engines.
If this page dynamically detects the language, then whatever language Google sees when it crawls is the language it will make the page as.
http://www.example.com/
If the site contains a query string flag for another language the site is likely to be crawled in both languages IF there is a link to the second language somewhere on your site. These are good examples (a separate domain is the best option) for showing Google where a Spanish page would reside.
http://es.example.com - best for SEO
http://www.example.com/?lang=es
http://www.example.com/es/
In your PHP code you’re only catching the initial 2 digit code for the preferred language of the browser. Some people actually read in more than one language (basically anyone who’s not American). They might have those other languages in their preferred languages, so while someone from France may have fr
as their preferred language, they may also understand English (en
), so their browser accepted string might look something like this in Chrome:
fr,en-US;q=0.8,en;q=0.6
or this in IE:
fr-FR,en-US;q=0.5
This code will check to see if they’ve set the $_GET
flag for the language and override the automatic translation. I found this code, then modified it to work for my purposes because the site where it’s being used is European where most people speak multiple languages. For this code I’ve modified it here, so if their preferred language isn’t Spanish it will default to English. This would go into a file like lang.php
which would get included on every page.
<?php
$langs = array();
if (!empty($_GET['lang'])){
$tempLang = $_GET['lang'];
//Setup the switch for all of the possible languages.
switch($tempLang){
case 'es':
$pref='es';
break;
default:
//english
$pref='en';
}
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)s*(;s*qs*=s*(1|0.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])) {
// create a list like "en" => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') $val = 1;
$lParse = strtolower(preg_replace('!-.*$!','',$lang));
if(!isset($newLangs[$lParse])){
$newLangs[$lParse] = $val;
}
}
// sort list based on value
arsort($newLangs, SORT_NUMERIC);
}
//Set the preferred languages for the website (available translations)
$preferred = array('en','es');
//Check for overlap keeping the preference order
$intersect = array_values(array_intersect(array_keys($newLangs), $preferred));
//print_r($newLangs);
if(isset($intersect[0])){
//Set the first preference
$pref = $intersect[0];
if(preg_match('!^es!',$pref)){
$pref='es';
}
} else {
//default to english
$pref = 'en';
}
} else {
//default to english
$pref = 'en';
}
?>
On the page including lang.php
you would need to check the $pref
variable to show the proper translation for the language.
Javascript
You can do a redirect with Javascript to make the page load the other language using this same code, however search engines typically only look at Javascript for exploits and won’t follow the links in the Javascript. According to Google Webmaster’s Guidelines:
Use a text browser such as Lynx to examine your site, because most
search engine spiders see your site much as Lynx would. If fancy
features such as JavaScript, cookies, session IDs, frames, DHTML, or
Flash keep you from seeing all of your site in a text browser, then
search engine spiders may have trouble crawling your site.
You can do the change with a click using AJAX, however the URL where AJAX would listen would need to be passed the parameter and these are usually passed via $_GET
variables.
IP Look-up
Another method some people have tried is to check the IP address and reverse look-up the location to see where the country of origin is, then they’ll pick the national language. The problems with this are:
- People travel
- Some IP addresses are registered to owners in other countries (think corporate blocks) rather than the country where the user is browser.
- Some of the IP address listings are highly inaccurate.
Cookies
Not all users accept cookies and some corporate firewalls may even strip the cookies.
Если на вашем сайте есть контент на нескольких языках, вам нужно использовать атрибут hreflang, чтобы поисковик выдавал пользователю нужную языковую версию.
В статье рассмотрим, что такое hreflang, зачем он нужен и как настроить его на сайте.
В статье:
-
Что такое hreflang и зачем он нужен
-
Кому стоит указывать hreflang
-
Особенности тегов hreflang
-
Как указать атрибут hreflang на сайте: три способа
-
Как проверить правильность hreflang на странице
Что такое hreflang и зачем он нужен
Hreflang — это атрибут HTML, которым маркируют страницы сайта с одинаковым контентом, но на разных языках. Атрибут hreflang помогает поисковикам выдавать пользователю версию страницы на понятном ему языке, соответствующую его геоположению. Поисковик анализирует сигналы каждого пользователя — страну и языковые настройки — и возвращает ему версию контента, которую считает наиболее подходящей.
Атрибут hreflang поддерживают Google и Яндекс. Но поисковики не рассматривают его как директиву, это только сигнал, к которому они могут прислушаться, а могут и проигнорировать.
Кому стоит указывать hreflang
Будет не лишним использовать атрибут hreflang, если на сайте есть страницы с одинаковым контентом, но на разных языках. Например, все украинские сайты по умолчанию должны быть на украинском языке. Но русскоязычные жители там тоже есть, так что обычно делают дополнительную версию на русском.
Еще вариант — язык один, но страницы для разных регионов различаются. Тогда тег hreflang может помочь избежать дублирования контента.
Допустим, вы работаете в буржунете и вам нужны разные страницы для пользователей из США и Великобритании. Они будут почти идентичны, поэтому Google может посчитать их дублями и выбрать только одну для индексации.
Нужно указать hreflang, чтобы помочь Google понять связь между ними, и локализовать содержимое: указать цены в нужной валюте, употребить названия и термины, которые приняты в этих регионах.
На страницах под США вы укажете цены в долларах и используете слова из американского английского, а на страницах для Великобритании будут фунты стерлингов и британский английский.
Если версии страницы отличаются только языком шаблона, тоже можно добавить hreflang. Например, если в блоге есть пользовательский контент, который не переводится, а шапка, подвал, кнопки и другая навигация показываются на разных языках.
Если язык страницы меняется в зависимости от IP-пользователя или на странице можно выбрать язык, тоже используют тег hreflang, но со значением “x-default”. Настройку разберем ниже.
Особенности тегов hreflang
Странице нужно добавить указание на себя
Строчка с hreflang не может быть одна. В Справке Яндекса указано, что в hreflang должны быть перечислены все версии страницы, включая текущую.
Если страница на русском продублирована на английском и украинском, на каждой из этих страниц должно быть три соответствующих элемента link с атрибутами локализации. То есть ссылка на себя и на две языковые альтернативы:
<link rel="alternate" hreflang="ru" href="https://ru.site.com/" />
<link rel="alternate" hreflang="en" href="https://en.site.com/" />
<link rel="alternate" hreflang="ua" href="https://ua.site.com/" />
Что означает каждая часть кода:
-
«alternate» — у этой страницы есть альтернативная версия;
-
hreflang = «ua» — альтернативная версия написана на украинском;
-
«https://ua.site.com/» — украинскую версию можно найти по этому URL.
Языковые коды указаны в стандарте ISO 639–1: ru — русский, de — немецкий, ua — украинский и так далее. Есть дополнительный список формата ISO 3166–1 alpha-2, когда нужно уточнить регион или страну: en-gb — английский контент для Великобритании, en-us — американский английский для США, de-es — контент на немецком для пользователей из Испании.
Регион уточняйте только после кода языка, а то может возникнуть путаница:
-
be — белорусский язык для любого региона;
-
fr-be — французский для жителей Бельгии.
В Google Search Central также написано:
«Каждая языковая версия должна указывать на себя, а также на все другие языковые версии».
Но Джон Мюллер в Твиттере сказал, что это хорошая практика, но не обязательная.
Self-referential hreflang is optional, but you’re right — it’s a good practice!
— John (@JohnMu) June 29, 2018
Слушать ли Мюллера — вопрос, но раз Яндекс и Google говорят, что нужно указать, то лучше так и сделать.
Теги hreflang работают только парами
Если есть две одинаковых страницы сайта на разных языках, на каждой нужно указать ссылку на вторую страницу.
Допустим, у вас есть русская и украинская версия контента. На страницу на русском языке вы добавляете тег hreflang, где указываете, что есть украинская версия страницы. А на странице для Украины в теге hreflang указываете, что есть русская альтернатива.
Если страницы не ссылаются друг на друга, поисковик проигнорирует тег. Это сделали, чтобы владелец чужого сайта не смог указать, якобы его страница на другом языке — альтернатива вашей.
Пример тега hreflang с указанием альтернативного варианта на украинском:
<link rel="alternate" hreflang="ru" href="https://site.ru/" />
<link rel="alternate" hreflang="ua" href="https://site.com/ua/" />
Тег hreflang нужен только на канонических страницах
Если страница каноническая и есть потребность в указании языковой версии, hreflang нужен. На дублирующих страницах указывать hreflang не нужно, поскольку он и так будет указан на канонической странице.
Все о rel canonical: как указывать атрибут правильно и зачем он нужен
Из этого и предыдущего правил понятно, как поступать с языковыми версиями для страниц с параметрами.
Как указать hreflang для URL с параметрами
Пользователь поднял эту тему на форуме.
На его сайте размещена каноническая страница https://example.com/au/publications для Австралии, у нее есть альтернативная версия для США https://example.com/us/publications. Но еще на этой странице есть кнопки, по которым пользователь может получить отдельные результаты — образуются URL с параметрами, например, https://example.com/au/publications?count=50&page=4.
Как в этом случае проставить hreflang?
Сначала для страницы с параметрами https://example.com/au/publications?count=50&page=4 он указал каноникал и hreflang:
<link rel="canonical" href="https://example.com/au/publications">
<link rel="alternate" hreflang="en-US" href="https://example.com/us/publications">
Но мы помним, что тег hreflang работает только в паре. Если на этой странице с параметрами указан hreflang со ссылкой на альтернативную версию для США, то и на версии для США должна быть ссылка на эту страницу с параметрами. А ее нет, поэтому в консоли ошибка.
Как нужно сделать в этом примере:
Просто не указывать hreflang для неканонических страниц с параметрами. Для URL https://example.com/au/publications?count=50&page=4 достаточно указать только каноническую ссылку:
<link rel="canonical" href="https://example.com/au/publications">
А для URL https://example.com/au/publications нужно указать каноникал:
<link rel="canonical" href="https://example.com/au/publications" />
И hreflang с каждой существующей языковой версией, а их две — для Австралии и США:
<link rel="alternate" hreflang="en-US" href="https://example.com/us/publications">
<link rel="alternate" hreflang="en-AU" href="https://example.com/au/publications">
Теперь Google видит, что страница с параметрами https://example.com/au/publications?count=50&page=4 — это дубликат страницы https://example.com/au/publications, так что он не будет ее индексировать.
И еще видит, что https://example.com/au/publications ориентирована на англоязычных пользователей из Австралии и имеет альтернативную версию для пользователей из США, доступную по адресу https://example.com/us/publications.
Структура сайта не важна
Структура сайта не влияет на обработку поисковиками атрибута hreflang. Версии страницы могут быть расположены в разных каталогах:
<link rel="alternate" hreflang="ru" href="https://site.com/o-kompanii/" />
<link rel="alternate" hreflang="en-us" href="https://site.com/company/about/" />
<link rel="alternate" hreflang="ua" href="https://site.com/pro-kompaniyu" />
Также версии страницы могут быть расположены на разных поддоменах и доменах:
<link rel="alternate" hreflang="ru" href="https://ru.site.com/" />
<link rel="alternate" hreflang="en" href="https://en.site.com/" />
<link rel="alternate" hreflang="ua" href="https://site.com.ua/" />
Для страниц с автоматическим определением языка есть свой hreflang
Если на странице есть селектор для выбора языка или язык меняется в зависимости от IP-пользователя, нужен hreflang со значением «x-default». Он указывает, какую страницу показывать по умолчанию или какую отображать, когда другой вариант языка не подходит пользователю.
К примеру, на главной сайта site.com язык меняется в зависимости от IP-адреса пользователя. Тогда ссылку на главную нужно отметить с «x-default», а также нужно указать на версии страниц на других языках:
<link rel="alternate" hreflang="x-default" href="https://site.com/" />
<link rel="alternate" hreflang="ru" href="https://site.com/ru/">
<link rel="alternate" hreflang="en" href="https://site.com/en/">
<link rel="alternate" hreflang="ua" href="https://site.com/ua/">
Как указать атрибут hreflang на сайте
Есть три способа реализовать атрибут hreflang:
-
в HTML;
-
в заголовках HTTP;
-
в файле Sitemap.
А для CMS есть плагины и модули, например:
-
WordPress: HREFLANG Tags Lite, Language Switcher, Juiz Lang Attribute;
-
OpenCart: Hreflang alternate link, SEO мультиязык, OCDEV.pro.
Как указать hreflang в HTML
Самый популярный способ — добавить hreflang в HTML каждой страницы, которым нужно указать альтернативные версии. Тег нужно добавить в начало секции head после Title и Description.
Допустим, есть сайт условной компании Super-Company, она работает на Россию, Германию и Великобританию. На нем сделаны региональные страницы с некоторыми отличиями:
-
https://ru.super-company.com/ — главная страница на русском языке с тарифами на доставку из России;
-
https://en-gb.super-company.com/ — страница для клиентов из Великобритании с ценами в фунтах стерлингов;
-
https://de.super-company.com/page.html — страница для клиентов из Германии с ценами в евро;
-
https://en.super-company.com/page.html — главная страница на английском языке;
-
https://www.super-company.com/ — страница по умолчанию, на которой пользователи могут выбрать нужный им язык и регион.
Такой код нужно поместить на каждую из этих страниц. Он будет отправлять пользователей из России, Германии, Великобритании, а также англоговорящих на нужные страницы, а пользователей из других стран на страницу по умолчанию, чтобы они сами выбрали язык.
<head>
<title>Super-Сompany</title>
<link rel="alternate" hreflang="ru" href="https://ru.super-company.com/">
<link rel="alternate" hreflang="en-gb" href="https://en-gb.super-company.com/">
<link rel="alternate" hreflang="de-de" href="https://de.super-company.com/">
<link rel="alternate" hreflang="en" href="https://en.super-company.com/">
<link rel="alternate" hreflang="x-default" href="https://www.super-company.com/">
</head>
Проблема этого способа в том, что если вы добавите еще одну версию страницы, придется редактировать код всех версий и добавлять ссылку на нее. А если у вас много версий на разных языках, работы неприятно прибавится.
Как указать hreflang в заголовках HTTP
Указать на версии страницы на других языках можно в заголовке HTTP в ответах на запрос GET страницы. Способ особенно выручает, если нельзя указать код в HTML, например, для файлов в формате PDF.
Для каждой версии страницы нужно указать набор значений < url >, rel = «alternate» и hreflang через запятую. Это касается и запрашиваемой страницы. Заголовок одинаковый для всех вариантов — Link:.
Шаблон такой:
HTTP/1.1 200 OK
Content-Type: application/pdf
Link: <url_1>; rel="alternate"; hreflang="lang_code_1",
<url_2>; rel="alternate"; hreflang="lang_code_2"
Допустим, на сайте есть три версии PDF-файла: для русскоязычных посетителей, отдельно для англоязычных пользователей из США и версия на английском для пользователей из других стран. Код будет выглядеть так:
HTTP/1.1 200 OK
Content-Type: application/pdf
Link: <https://site.com/file.pdf>; rel="alternate"; hreflang="ru",
<https://en-us.site.com/file.pdf>; rel="alternate"; hreflang="en-us",
<https://en.site.com/file.pdf>; rel="alternate"; hreflang="en"
Как указать hreflang в Карте сайта — sitemap.xml
Указать языковую принадлежность страниц можно в файле Sitemap. Нужно добавить в карту элемент с URL страницы, а в дочерних тегах указать ссылки на все ее языковые варианты, включая саму эту страницу.
Порядок перечисления языковых версий в дочерних элементах не имеет значения, но лучше придерживаться какой-то системы, чтобы не запутаться.
Пространство имен xhtml нужно указывать по образцу:
xmlns:xhtml="http://www.w3.org/1999/xhtml"
Получается, если у страницы три языковых варианта — русский, английский и украинский — в Sitemap будет три элемента с тремя дочерними тегами.
-
https://site.com/ru/ — для аудитории, говорящей по-русски;
-
https://site.com/en/ — для англоговорящей аудитории;
-
https://site.com/ua/ ;— для тех, кто говорит на украинском языке.
Пример Sitemap для этих трех страниц:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="https://www.w3.org/1999/xhtml">
<url>
<loc>https://site.com/ru/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://site.com/en/">
<xhtml:link rel="alternate" hreflang="ua" href="https://site.com/ua/">
<xhtml:link rel="alternate" hreflang="ru" href="https://site.com/ru/">
</url>
<url>
<loc>https://site.com/en/</loc>
<xhtml:link rel="alternate" hreflang="ru" href="https://site.com/ru/">
<xhtml:link rel="alternate" hreflang="ua" href="https://site.com/ua/">
<xhtml:link rel="alternate" hreflang="en" href="https://site.com/en/">
</url>
<url>
<loc>https://site.com/ua/</loc>
<xhtml:link rel="alternate" hreflang="ru" href="https://site.com/ru/">
<xhtml:link rel="alternate" hreflang="en" href="https://site.com/en/">
<xhtml:link rel="alternate" hreflang="ua" href="https://site.com/ua/">
</url>
</urlset></xhtml:link></xhtml:link></xhtml:link></xhtml:link></xhtml:link></xhtml:link></xhtml:link></xhtml:link></xhtml:link></urlset>
Легко запутаться, но зато не нужно редактировать несколько HTML-документов каждый раз, когда вы добавляете новую версию или удаляете страницу.
Если вы еще не сформировали файл Sitemap, может быть полезно:
Как составить Карту сайта
Как проверить правильность hreflang на странице
Подождите, пока Google просканирует страницы, загляните в отчет «Таргетинг по странам и языкам» в консоли Google и откройте вкладку «Язык» — там будут отображаться ошибки.
Для поиска ошибок в HTML есть валидатор Html Checker, сервис hreflang.ninja, hreflang Tags Testing Tool.
Делитесь материалом и оставляйте свои отзывы в комментариях, будем рады!