【问题标题】:Filtering a list of strings based on user locale根据用户区域过滤字符串列表
【发布时间】:2018-04-29 23:42:27
【问题描述】:

在使用 AngularJS 1.6 处理 JavaScript 项目时,我有一个要过滤的字符串列表。例如,假设我的列表包含 árbolcigüeñanidotubo

在过滤西班牙语字符串时,如果我过滤“u”,我希望 cigüeñatubo 都会出现,这将是最自然的结果一个西班牙人。但是,在德语中情况并非如此 - u 和 ü 是不同的字母,因此德国人不会希望在列表中看到 cigüeña。所以我正在寻找一种方法让我的列表过滤了解用户的语言环境。

我碰巧有一个包含很多变音符号的对象,例如:

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;
}

很遗憾,这不起作用。在将“u”和“ü”与德语和西班牙语语言环境进行比较时,localeCompare 函数返回相同的值,所以这不是这里的答案。我查看了reference for the localeCompare method 并尝试了用法和灵敏度选项,但它们在这里似乎没有太大帮助。

如何调整我的代码以使其正常工作?有没有图书馆可以为我妥善处理这个问题?

【问题讨论】:

    标签: javascript angularjs internationalization


    【解决方案1】:

    我将通过navigator (src) 直接从浏览器获取用户的语言环境,这是一个代表用户代理的对象:

    var language = navigator.language;
    

    这将分配language 用户浏览器的区域设置代码,在我的情况下为en-US。我发现this site 有助于查找语言环境代码以测试世界其他地区。

    我的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 函数中看到的那样,当且仅当Intl.Collator 的结果为0 时,它才返回true,表明该字母在该语言的字母表中没有位置差异,这意味着它可以安全更换。

    有了这个,下面是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
    

    【讨论】:

    • 我认为你上次的 sn-p 有一个小错误。我认为“位置”变量应该称为“语言”。除此之外,它是完美的!
    • @unpollito 哎呀,现在修复了
    【解决方案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
    

    然后,您可以在填充 UI 小部件之前将列表排序为正确的顺序。

    【讨论】:

    • 很遗憾,这不起作用。这与我在 localeCompare() 位中提到的基本相同:比较“u”和“ü”时,西班牙语和德语的结果相同。 Collat​​or 和 localeCompare() 都会发生这种情况,这并不奇怪,因为它们是同一个 API 的一部分。
    • 阅读 Cole 的回答后,我意识到我的方法和您的解决方案都缺少同时使用 usage="search" 和 Sensitivity="base"。一旦我们这样做了,整理者就可以意识到西班牙语和德语的“u”和“ü”之间的区别,如果我们将“用法”排除在外,就不会发生这种情况。
    猜你喜欢
    • 1970-01-01
    • 2011-01-10
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    相关资源
    最近更新 更多