Главная » Статьи » Создание фильтра i18n с использованием Vue.js и оригинальных веб-спецификаций

Создание фильтра i18n с использованием Vue.js и оригинальных веб-спецификаций

Создание фильтра i18n с использованием Vue.js и оригинальных веб-спецификаций

От автора: я все еще изучаю Vue, и одна из вещей, которые я принялся изучать с небольшим запоздание, это фильтры. (Возможно это потому, что они описываются в самом конце документации!) Фильтры, как вы можете догадаться, позволяют вам определять простые текстовые преобразования для значений. Так, например, в этой спецификации описан фильтр Capitalization, который преобразует первую букву строки в верхний регистр. Vue не поставляется с встроенными фильтрами, но их невероятно легко написать. Это является большим преимуществом для интернационализации и глобализации, мы можем гибко определять форматирование значений на предпочтительном языке пользователя.

Это помогает предотвратить такие проблемы, как, например, сложности при идентификации такой даты: 4/8/73. Для американцев это 8 апреля 1973 года. Для значительной части остальной части планеты эта дата — 4 августа 1973 года. Было бы неплохо, если бы мы могли просто автоматически форматировать эти значения соответствующим образом для наших пользователей. Тут может прийти на помощь фильтр Vue i18n.

Конечно, все это не новая проблема, и для этого существуют несколько библиотек. Невероятная Moment.js отлично поддерживается уже сейчас. Но знаете ли вы, что есть возможность использовать для этого веб-стандарты? Спецификация Intl существует около шести лет, но ее поддержка браузерами до недавнего времени была недостаточной. Но последний отчет CanIUse.com указывает, что ее поддержка улучшилась уже до вполне приемлемых 85%.

Учитывая этот уровень поддержки, уже можно вполне надежно использовать ее в наших приложениях. Мы можем реализовать проверку поддержки Intl с помощью if(window.Intl) и в качестве резервного варианта … ну, просто отображать значение как есть. Вы должны решить для себя, подходит ли вам такая стратегия.

Спецификация Intl позволяет нам форматировать даты, числа и валюты. Она также поддерживает обработку специфичных для локали сортировки и плюрализации. Только, помните, что вы не можете просто «конвертировать» американские доллары в евро. Да, я совершал подобную ошибку раньше. Так что, учитывая, что у нас есть неплохой нативный способ интернационализации значений, и у нас есть Vue — как мы можем создать некоторые фильтры для поддержки этого?

Исходная версия

Начнем с создания простой демо-версии без форматирования. Я начал с простого представления, которое отображало три значения: дату, число и валюту. Я также добавил несколько простых полей формы для быстрого редактирования пользователем.

<div id="app"> <p>The date is {{ date }}.</p> <p>We've had {{ accidentFree }} accident free days!</p> <p>You're current debt is ${{ debt }}.</p> <hr/> <p> Use to change values above: </p> <p> Date: <input v-model="date"><br/> Accident Free Days: <input v-model="accidentFree"><br/> Debt: <input v-model="debt"><br/> </p> </div>

Код Vue просто устанавливает начальные значения:

const app = new Vue({ el:'#app', data:{ date:new Date(), debt:999999999, accidentFree:3232 }
})

Вы можете поэкспериментировать с этим кодом прямо сейчас, используя встроенный ниже блок CodePen:

Обратите внимание, что даже если мы не заботимся совсем обо всем мире, даже для меня это выглядит не очень хорошо. Например, сума задолженности не очень читаема. Это 9 миллиардов или 9 триллионов? Дата, конечно, читабельная, но не очень красивая. Давайте возьмем эту версию за основу и начнем добавлять фильтры!

Крутая версия

Vue позволяет нам определять фильтры либо глобально, либо на основе каждого компонента. Для простоты мы будем определять фильтры глобально, используя этот формат:

Vue.filter('nameOfAwesomeFilter', s => { //logic here, return the result
});

Приведенный выше код позволяет нам использовать фильтр следующим образом: {{ boringValue |nameOfAwesomeFilter }}. Вы также можете использовать его в привязке: v-bind:label=»boringValue | nameOfAwesomeFilter». Также обратите внимание, что здесь я использую функцию стрелки (например, hipster), и это абсолютно не то, что вам нужно. Для первого фильтра мы определим одну вызываемую дату:

Vue.filter('date', s => { if(!window.Intl) return s; // convert to date if(!(s instanceof Date)) { let orig = s; s = new Date(s); if(s == 'Invalid Date') return orig; } return new Intl.DateTimeFormat().format(s);
});

В верхней части у нас есть несколько простых функций проверки поддержки для Intl API. Как я уже сказал, резервный вариант — просто вернуть начальное значение, и, хотя это может быть не оптимальным, это быстрое решение для малого числа людей, использующих старые браузеры. (Еще один прием, который вы можете рассмотреть — добавить в конце текст, который указывает, что дата отображается в американском формате.)

Дальше немного более сложная часть. Наша демо-версия позволяет пользователю вводить новую дату, что означает, что это значение может быть строкой, а не датой, как указано в определении компонента Vue. Строку преобразовать в дату достаточно легко, но JavaScript позволяет преобразовать в дату что угодно. Подобные несоответствия обрабатываются каким-либо методом проверки наподобие “Invalid Date”. Примечание. Я также сохраняю исходное значение, чтобы оно могло быть возвращено вместо «плохого» объекта даты.

Наконец, мы просто создаем экземпляр DateTimeFormat и запускаем для него форматирование. По умолчанию объект DateTimeFormat будет использовать текущие локаль и формат даты в сокращенной форме: 2/20/2018. Вы можете указать другие форматы, в этом вам поможет документация MDN. Обратите внимание, что для указания параметров даты требуется указать локаль. Дальше я расскажу о проблеме которая возникает при преобразовании валюты, поэтому обратите внимание на это решение.

Применить сам фильтр довольно просто, для этого нужно добавить пайп и имя фильтра:

<p>The date is {{ date | date }}.</p>

Мне не очень нравится, что date используется дважды, но я предполагаю, что в реальном приложении значение данных Vue, вероятно, будет иметь другое имя. Дальше мы обрабатывает формат чисел — здесь все намного проще:

Vue.filter('number', s => { if(!window.Intl) return s; return new Intl.NumberFormat().format(s);
});

Мы использовали объект NumberFormat со всеми значениями по умолчанию. Как и в объекте DateTimeFormat, здесь присутствуют параметры. В нашей демо-версии этот код возвращает (опять же для американцев): “We’ve had 3,232 accident free days!”. В других локациях вы будете видеть: “We’ve had 3 232 accident free days!” Как и раньше, применить фильтр просто:

<p>We've had {{ accidentFree | number }} accident free days!</p>

И, наконец, давайте рассмотрим форматирование валюты. Чтобы полностью все прояснить — это форматирование валюты, а не конвертация валюты. Пожалуйста, перечитайте это предложение несколько раз. Для этого мы используем NumberFormat, но указываем параметр — форматировать, как валюту. Для этого нужно изменить две вещи.

Чтобы передать параметры NumberFormat, мы должны передать первый аргумент, который представляет используемый язык. К сожалению, встроенной функции типа «getCurrentLocale» для этого не существует. Я использовал это решение StackOverflow, поскольку это было довольно просто:

//https://stackoverflow.com/a/31135571/52160
function getLang() { if (navigator.languages != undefined) return navigator.languages[0]; else return navigator.language;
}

Теперь с помощью этой функции мы можем передать первый аргумент, а затем параметры валюты. Вы должны указать, какую валюту вы используете, и для целей демонстрации я выбираю Евро. Вот фильтр.

Vue.filter('currency', s => { let result = new Intl.NumberFormat(getLang(), {style:'currency',currency:'EUR'}).format(s); return result;
});

Обратите внимание, что параметры передаются как простой объект во втором аргументе. Вы можете прочитать о других возможных вариантах в документации на MDN. Каков результат? — “Your current debt is €999,999,999.00″. Вы можете поэкспериментировать с этой демо-версией:

В качестве примечания — фильтры в демо-версии запускаются при каждом отдельном вводе данных в поля формы. Хотя это не имеет значения для демо-версии, в реальном приложении это может вызвать проблемы с производительностью. Вы также можете кэшировать создание DateTimeFormatter и NumberFormatter, чтобы вам нужно было использовать функцию форматирования только для этих глобальных объектов. Пожалуйста, не стесняйтесь — работайте с моими CodePens и расскажите, что у вас получилось!

Надеюсь, эти примеры дали вам понимание того, как легко использовать фильтры Vue. Я хотел бы прочитать ваши комментарии о любых уникальных фильтрах, которые вы, возможно, создали.

Автор: Raymond Camden

Источник: https://vuejsdevelopers.com/

Редакция: Команда webformyself.