Найкращий спосіб визначити локальність користувача в браузері


202

У мене веб-сайт (Flash), локалізований на десятках мов, і я хочу автоматично визначити значення за замовчуванням залежно від налаштувань браузера користувача, щоб мінімізувати кроки доступу до вмісту.

FYI, я не можу використовувати серверні скрипти через обмеження проксі, тому я думаю, що JavaScript або ActionScript було б доречним для вирішення проблеми.

Запитання:

  1. Що було б найкращим методом «відгадати» локальний стан користувача?

  2. Чи існують якісь прості класи / функції, які могли б допомогти мені (немає складних пакетів локалізації)? Спеціально для розбиття всіх можливих мов на меншу кількість (у мене є переклади) на розумний спосіб.

  3. До якого моменту я можу довірити таке рішення?

  4. Будь-які інші шляхи вирішення чи пропозиції?


Єдиний спосіб, коли браузер може обмінюватися метаданими про свого користувача, і запит здійснюється через URL-адреси та заголовки. Візьміть Firefox і зазирніть до заголовків, що надсилаються, коли буде зроблено запит. Досить цікаво розглянути типові заголовки запитів та відповідей.
мП.

Відповіді:


188

Правильним способом є перегляд заголовка мови прийому HTTP, що надсилається на сервер. Він містить упорядкований, зважений список мов, які користувач налаштував на свій веб-переглядач.

На жаль, цей заголовок недоступний для читання в JavaScript; все, що ви отримуєте navigator.language, це говорить про те, яка локалізована версія веб-браузера була встановлена. Це не обов'язково те саме, що бажана мова (мови) користувача. На IE ви натомість отримуєте systemLanguage(встановлена ​​ОС мова), browserLanguage(те саме, що language) і userLanguage(налаштована користувачем область ОС), які всі так само не корисні.

Якби мені довелося вибирати між цими властивостями, я б понюхав userLanguageспочатку, повернувшись до нього languageі лише після цього (якщо вони не відповідали жодній доступній мові), дивлячись browserLanguageі, нарешті systemLanguage.

Якщо ви можете помістити сценарій на стороні сервера де-небудь ще в мережі, який просто зчитує заголовок Accept-Language і видаляє його назад як файл JavaScript зі значенням заголовка в рядку, наприклад:

var acceptLanguage= 'en-gb,en;q=0.7,de;q=0.3';

тоді ви можете включити <script src>, що вказує на цю зовнішню службу в HTML, і використовувати JavaScript для розбору заголовка мови. Я не знаю жодного існуючого бібліотечного коду для цього, оскільки розбір мови Accept майже завжди робиться на стороні сервера.

Що б ви в кінцевому підсумку не робили, вам, безумовно, потрібна переоцінка користувача, оскільки це завжди здогадується неправильно для деяких людей. Найчастіше найпростіше ввести мовну настройку в URL (наприклад, http: //www.example.com/uk/site vs http: //www.example.com/de/site), і дозволити користувачу натиснути зв’язки між ними. Іноді ви хочете отримати єдину URL-адресу для обох мовних версій; у цьому випадку вам потрібно зберегти налаштування у файлах cookie, але це може заплутати користувачів-агентів без підтримки файлів cookie та пошукових систем.


11
Від MDN developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/… "Заголовок HTTP-мови прийому у кожному запиті HTTP з браузера користувача використовує те саме значення для властивості navigator.languages, за винятком додаткової qvalues ​​(значення якості) поле (наприклад, en-US; q = 0,8). "
S Meaden

3
Оновлення. Зараз (2020 р.) Існує експериментальна функція, яка підтримується всіма сучасними браузерами, яка повертає масив мовних переваг: navigator.languages //["en-US", "zh-CN", "ja-JP"]це має працювати як мінімум на 95% браузерів у 2020 році.
Корнелій Ромер,

1
navigator.languages, за даними MDN та caniuse.com , тепер доступний у всіх основних браузерах - спробуйте крихітний (~ 200 байт) пакет мов навігатора для найсучаснішого та сумісного назад підходу.
mindplay.dk

84

У Chrome і Firefox 32+, navigator.languages ​​містить масив локалів у порядку користувальницьких налаштувань і є більш точним, ніж navigator.language, однак для того, щоб зробити його сумісним із зворотним ходом (випробуваний Chrome / IE / Firefox / Safari), а потім використовуйте це:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}

2
Це не працює для IE9 та IE10. Для них вам доведеться перевірити navigator.browserLanguage.
користувач393274

2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza

4
@ChStark Чи не так return navigator.languages[0] || navigator.language;?
Джеймс_

23
Крім того , правильний «один вкладиш» буде виглядати наступним чином : return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;. Інакше ви отримуєте виняток, якщо він navigator.languagesне визначений або порожній.
Макс Трукса

Для ще більш компактної версіїconst getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
João Miguel Brandão

41

Ця стаття пропонує наступні властивості об’єкта навігатора браузера :

  • navigator.language (Netscape - Локалізація браузера)
  • navigator.browserLanguage (специфічний для IE - локалізована мова браузера)
  • navigator.systemLanguage (Специфічний для IE - ОС Windows - Локалізована мова)
  • navigator.userLanguage

Згорніть їх у функцію javascript, і ви повинні мати можливість вгадати правильну мову у більшості випадків. Не забудьте виграшно виграти, тому створіть розділ, який містить посилання на вибір мови, так що якщо немає JavaScript або метод не працює, користувач може все-таки прийняти рішення. Якщо це все-таки спрацює, просто схойте діву.

Єдина проблема з цим на клієнтській стороні полягає в тому, що або ви обслуговуєте всі мови для клієнта, або вам доведеться почекати, поки скрипт запуститься і виявить мову, перш ніж запитувати потрібну версію. Можливо, подання найпопулярнішої мовної версії за замовчуванням роздратує найменших людей.

Редагувати: я б другий пропозицією файлів cookie Івана, але переконайтеся, що користувач завжди може змінити мову пізніше; не кожен надає перевагу мові, яку налаштовано за допомогою браузера.


Дякую Філу за ваші пропозиції. Щодо статті, їй 6 років ... не впевнені, що ми можемо на неї покластися?
Theo.T

1
Я підозрюю, що сучасні браузери всі підтримують navigator.language. Мій браузер (FF3 на Ubuntu 8.10) повідомляє "en-GB". Якщо хтось досі використовує IE6 - близько 20% людей - тоді це варто дозволити. IE6 з'явився 8 років тому.
Філ Х

IE 8 не підтримує navigator.language. Можливо, IE 9 буде?
шпига

36

Комбінуючи кілька способів, якими користуються браузери для зберігання мови користувача, ви отримуєте цю функцію:

const getNavigatorLanguage = () => {
  if (navigator.languages && navigator.languages.length) {
    return navigator.languages[0];
  } else {
    return navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
  }
}

Спочатку перевіряємо navigator.languagesмасив на його перший елемент.
Тоді отримуємо navigator.userLanguageабо navigator.language.
Якщо це не вдасться, ми отримуємо navigator.browserLanguage.
Нарешті, ми встановлюємо це, 'en'якщо все інше не вдалося.


А ось і сексуальний одноколісний:

const getNavigatorLanguage = () => (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';

мабуть, є також щось на зразок navigator.userLanguage(для IE). Ви можете додати це для завершення :)
pors

Чому б не просто navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'?
Emerica

@Curse Тому що navigator.languagesможе бутиundefined
Zenoo

@ Zenoo Чи знаєте ви, в яких браузерах?
Emerica

(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Стів Беннетт

10

Існує різниця між бажаними мовами користувача та локальною системою / браузером.

Користувач може налаштувати бажані мови у браузері, і вони будуть використовуватися для navigator.language(s)запиту ресурсів із сервера для запиту вмісту відповідно до списку мовних пріоритетів.

Однак, локальний режим браузера вирішить, як відобразити номер, дату, час та валюту. Цей параметр є, ймовірно, мовою найвищого рейтингу, але гарантій немає. У Mac та Linux система визначає локальний ланд незалежно від переваг мови користувача. У Windows можна обирати серед мов у списку бажаних в Chrome.

Використовуючи Intl ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl ), розробники можуть змінити / встановити локаль, який використовується для візуалізації цих речей, але є елементи, які не можна перекрити, наприклад <input type="date">формат.

Для правильного вилучення цієї мови я знайшов єдиний спосіб:

(new Intl.NumberFormat()).resolvedOptions().locale

( Intl.NumberFormat().resolvedOptions().localeтакож, здається, працює)

Це створить новий екземпляр NumberFormat для локальної мови за замовчуванням, а потім зчитує локальну мову цих вирішених параметрів.


5

Я трохи провів дослідження з цього приводу, і я підсумував свої висновки донизу в таблиці нижче

введіть тут опис зображення

Тому рекомендованим рішенням є написання сценарію на серверному сервері для розбору Accept-Languageзаголовка та передачі його клієнтові для встановлення мови веб-сайту. Дивно, що для того, щоб сервер знадобився для виявлення мовних уподобань клієнта, але це так, як зараз. Існують інші різні хаки для виявлення мови, але читання Accept-Languageзаголовка є рекомендованим рішенням, наскільки я розумію.


2

Ви також можете спробувати отримати мову з документа, який може бути вашим першим портом дзвінка, а потім повернутися до інших засобів, оскільки часто люди хочуть, щоб їх мова JS відповідала мові документа.

HTML5:

document.querySelector('html').getAttribute('lang')

Спадщина:

document.querySelector('meta[http-equiv=content-language]').getAttribute('content')

Жодне справжнє джерело не обов'язково на 100% надійне, оскільки люди можуть просто викласти невірною мовою.

Існують бібліотеки виявлення мови, які можуть дозволяти вам визначати мову за змістом.


1

Я використав усі відповіді та створив єдине рядкове рішення:

const getLanguage = () => navigator.userLanguage || (navigator.languages && navigator.languages.length && navigator.languages[0]) || navigator.language || navigator.browserLanguage || navigator.systemLanguage || 'en';

console.log(getLanguage());

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.