Фильтрация списка строк на основе пользовательской локали
При работе над проектом JavaScript с AngularJS 1.6 у меня есть список строк, которые я хотел бы фильтровать. Например, предположим, что мой список содержит раббол, сиганю, нидо и тубо.
При фильтрации строк на испанском языке, если бы я отфильтровал "u", я ожидал появления как сигаью, так и тубо, что было бы самым естественным результатом для испанца. Однако это не так на немецком языке - u и ü - разные буквы, и, таким образом, немецкий не захочет видеть сигареты в списке. Поэтому я ищу способ настроить фильтрацию списка в пользовательской локали.
У меня есть объект, содержащий множество диакритических знаков, например:
diacritics["á"] = "a";
diacritics["ü"] = "u";
// and so on...
Вот как выглядит мой код фильтрации:
function matches(word, search) {
var cleanWord = removeDiacritics(word.toLowerCase());
var cleanSearch = removeDiacritics(search.toLowerCase());
return cleanWord.indexOf(cleanSearch) > -1;
}
function removeDiacritics(word) {
function match(a) {
return diacritics[a] || a;
}
return text.replace(/[^\u0000-\u007E]/g, match);
}
Вышеприведенный код просто удаляет все диакритики, поэтому я думал, чтобы он знал о локали пользователя. Таким образом, я изменил функцию match() на это:
function match(a) {
if (diacritics[a] && a.localeCompare(diacritics[a] === 0) {
return diacritics[a];
}
return a;
}
К сожалению, это не работает. Функция localeCompare возвращает те же значения при сравнении "u" и "ü" с немецкими и испанскими локалями, так что это не был ответ здесь. Я просмотрел ссылку для метода localeCompare и попробовал варианты использования и чувствительности, но они, похоже, не помогают здесь.
Как я могу настроить мой код для этого? Есть ли библиотека, которая может справиться с этим правильно для меня?
Ответы
Ответ 1
Я хотел бы получить локализацию пользователя непосредственно из браузера через navigator
(src), объект, представляющий пользовательский агент
var language = navigator.language;
Это присвоит language
код языковой версии браузера пользователя, в моем случае en-US
. Я нашел этот сайт полезен для поиска кода локали для тестирования других регионов мира.
Моя функция strFromLocale
сравнима с вашей функцией removeDiacritics
:
function strFromLocale(str) {
function match(letter) {
function letterMatch(letter, normalizedLetter) {
var location = new Intl.Collator(language, {usage: 'search', sensitivity: 'base' }).compare(letter, normalizedLetter);
return (location == 0)
}
normalizedLetter = letter.normalize('NFD').replace(/[\u0300-\u036f]/gi, "")
if ( letterMatch(letter, normalizedLetter) ) {
return normalizedLetter;
} else {
return letter;
}
}
return str.replace(/[^\u0000-\u007E]/g, match);
}
Обратите внимание на строку с Intl.Collator
(src). Эта линия сравнивает диакритику с нормированной буквой диакритики и проверяет данный алфавит языка для позиционных различий. Поэтому:
/* English */
new Intl.Collator('en-US', {usage: 'search', sensitivity: 'base' }).compare('u', 'ü');
>>> 0
/* Swedish */
new Intl.Collator('sv', {usage: 'search', sensitivity: 'base' }).compare('u', 'ü');
>>> -1
/* German */
new Intl.Collator('de', {usage: 'search', sensitivity: 'base' }).compare('u', 'ü');
>>> -1
Как вы можете видеть в функции letterMatch
, она возвращает true тогда и только тогда, когда результат Intl.Collator
равен 0
, что указывает на отсутствие позиционных отличий буквы в алфавите этого языка, что означает безопасно заменять.
С этим, вот некоторые тесты функции strFromLocale
:
var language = navigator.language; // en-US
strFromLocale("cigüeña");
>>> ciguena
var language = 'sv' // Swedish
strFromLocale("cigüeña");
>>> cigüena
var language = 'de' // German
strFromLocale("cigüeña");
>>> cigüena
var language = 'es-mx' // Spanish - Mexico
strFromLocale("cigüeña");
>>> cigueña
Ответ 2
Вероятно, вы ищете библиотеку ECMA 6 Intl. Это позволит вам настроить порядок сортировки на основе языка, например:
// in German, ä sorts with a
console.log(new Intl.Collator('de').compare('ä', 'z'));
// → a negative value
// in Swedish, ä sorts after z
console.log(new Intl.Collator('sv').compare('ä', 'z'));
// → a positive value
Опция sensitivity: 'base'
будет автоматически сортироваться с/без диакритики.
// in German, ä has a as the base letter
console.log(new Intl.Collator('de', { sensitivity: 'base' }).compare('ä', 'a'));
// → 0
// in Swedish, ä and a are separate base letters
console.log(new Intl.Collator('sv', { sensitivity: 'base' }).compare('ä', 'a'));
// → a positive value
Затем вы можете отсортировать свой список в правильном порядке до заполнения вашего Виджета пользовательского интерфейса.