Drop Moment.JS, use custom small lib for relative dates and formatting
This commit is contained in:
parent
2ccc4110d6
commit
f0fc8f287d
@ -19,7 +19,6 @@
|
||||
"gps-to-gpx": "^1.4.0",
|
||||
"howler": "^2.0.15",
|
||||
"material-icons": "^0.2.3",
|
||||
"moment": "^2.22.2",
|
||||
"nosleep.js": "^0.7.0",
|
||||
"ol": "^5.1.3",
|
||||
"roboto-fontface": "^0.9.0",
|
||||
|
@ -49,10 +49,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { Howl } from 'howler';
|
||||
|
||||
import { REPORT_TYPES, REPORT_ALARM_VIBRATION_SEQUENCE } from '@/constants';
|
||||
import { distanceInWordsToNow } from '@/tools/date';
|
||||
import beepSound from '@/assets/beep.mp3';
|
||||
|
||||
export default {
|
||||
@ -62,7 +62,7 @@ export default {
|
||||
if (reportID != null) {
|
||||
const report = this.$store.state.reports.find(item => item.id === reportID);
|
||||
return {
|
||||
fromNow: moment(report.attributes.datetime).fromNow(),
|
||||
fromNow: distanceInWordsToNow(Date.parse(report.attributes.datetime)),
|
||||
icon: this.icons[report.attributes.type],
|
||||
id: report.id,
|
||||
label: this.$t(`reportLabels.${report.attributes.type}`),
|
||||
|
@ -69,6 +69,15 @@
|
||||
"preventSuspendDescription": "When the map is displayed, the device will be prevented from going to sleep.",
|
||||
"vibrate": "Vibrate"
|
||||
},
|
||||
"relativeDate": {
|
||||
"ago": "{duration} ago",
|
||||
"second": "one second | {count} seconds",
|
||||
"minute": "one minute | {count} minutes",
|
||||
"hour": "one hour | {count} hours",
|
||||
"day": "one day | {count} days",
|
||||
"month": "one month | {count} months",
|
||||
"year": "one year | {count} years"
|
||||
},
|
||||
"reportCard": {
|
||||
"Reported": "Reported {fromNow}."
|
||||
},
|
||||
|
@ -69,6 +69,15 @@
|
||||
"preventSuspendDescription": "Quand la carte est affich\u00e9e, l'appareil ne pourra pas passer en veille automatiquement.",
|
||||
"vibrate": "Vibrer"
|
||||
},
|
||||
"relativeDate": {
|
||||
"ago": "il y a {duration}",
|
||||
"day": "un jour | {count} jours",
|
||||
"hour": "une heure | {count} heures",
|
||||
"minute": "une minute | {count} minutes",
|
||||
"month": "un mois | {count} mois",
|
||||
"second": "une seconde | {count} secondes",
|
||||
"year": "un an | {count} ans"
|
||||
},
|
||||
"reportCard": {
|
||||
"Reported": "Signal\u00e9 {fromNow}."
|
||||
},
|
||||
|
@ -1,35 +1,27 @@
|
||||
import Vue from 'vue';
|
||||
import VueI18n from 'vue-i18n';
|
||||
|
||||
// Moment locales
|
||||
import 'moment/locale/en-gb';
|
||||
import 'moment/locale/fr';
|
||||
|
||||
// App locales
|
||||
import en from './en.json';
|
||||
import fr from './fr.json';
|
||||
import oc from './oc.json';
|
||||
|
||||
// Local moment locales
|
||||
import './moment/oc';
|
||||
|
||||
export const AVAILABLE_LOCALES = [
|
||||
{
|
||||
iso: 'en',
|
||||
name: 'English',
|
||||
export const AVAILABLE_LOCALES = {
|
||||
en: {
|
||||
messages: en,
|
||||
name: 'English',
|
||||
},
|
||||
{
|
||||
fr: {
|
||||
iso: 'fr',
|
||||
name: 'Français',
|
||||
messages: fr,
|
||||
name: 'Français',
|
||||
},
|
||||
{
|
||||
oc: {
|
||||
iso: 'oc',
|
||||
name: 'Occitan',
|
||||
messages: oc,
|
||||
name: 'Occitan',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export function getBrowserLocales() {
|
||||
let langs = [];
|
||||
@ -59,8 +51,8 @@ export function getBrowserLocales() {
|
||||
Vue.use(VueI18n);
|
||||
|
||||
export const messages = {};
|
||||
AVAILABLE_LOCALES.forEach((item) => {
|
||||
messages[item.iso] = item.messages;
|
||||
Object.keys(AVAILABLE_LOCALES).forEach((iso) => {
|
||||
messages[iso] = AVAILABLE_LOCALES[iso].messages;
|
||||
});
|
||||
|
||||
export default new VueI18n({
|
||||
|
@ -1,80 +0,0 @@
|
||||
//! moment.js locale configuration
|
||||
//! locale : Occitan, lengadocian dialecte [oc-lnc]
|
||||
//! author : Quentí
|
||||
/* eslint-disable */
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
export default moment.defineLocale('oc', {
|
||||
months : {
|
||||
standalone: 'genièr_febrièr_març_abril_mai_junh_julhet_agost_setembre_octòbre_novembre_decembre'.split('_'),
|
||||
format: 'de genièr_de febrièr_de març_d\'abril_de mai_de junh_de julhet_d\'agost_de setembre_d\'octòbre_de novembre_de decembre'.split('_'),
|
||||
isFormat: /D[oD]?(\s)+MMMM/
|
||||
},
|
||||
monthsShort : 'gen._febr._març._abr._mai._junh._jul._ag._set._oct._nov._dec.'.split('_'),
|
||||
monthsParseExact : true,
|
||||
weekdays : 'dimenge_diluns_dimars_dimècres_dijòus_divendres_dissabte'.split('_'),
|
||||
weekdaysShort : 'dg._dl._dm._dc._dj._dv._ds.'.split('_'),
|
||||
weekdaysMin : 'dg_dl_dm_dc_dj_dv_ds'.split('_'),
|
||||
weekdaysParseExact : true,
|
||||
longDateFormat : {
|
||||
LT : 'H:mm',
|
||||
LTS : 'H:mm:ss',
|
||||
L : 'DD/MM/YYYY',
|
||||
LL : 'D MMMM [de] YYYY',
|
||||
ll : 'D MMM YYYY',
|
||||
LLL : 'D MMMM [de] YYYY [a] H:mm',
|
||||
lll : 'D MMM YYYY, H:mm',
|
||||
LLLL : 'dddd D MMMM [de] YYYY [a] H:mm',
|
||||
llll : 'ddd D MMM YYYY, H:mm'
|
||||
},
|
||||
calendar : {
|
||||
sameDay : function () {
|
||||
return '[uèi a] LT';
|
||||
},
|
||||
nextDay : function () {
|
||||
return '[deman a] LT';
|
||||
},
|
||||
nextWeek : function () {
|
||||
return 'dddd [a] LT';
|
||||
},
|
||||
lastDay : function () {
|
||||
return '[ièr a] LT';
|
||||
},
|
||||
lastWeek : function () {
|
||||
return 'dddd [passat a] LT';
|
||||
},
|
||||
sameElse : 'L'
|
||||
},
|
||||
relativeTime : {
|
||||
future : 'd\'aquí %s',
|
||||
past : 'fa %s',
|
||||
s : 'unas segondas',
|
||||
ss : '%d segondas',
|
||||
m : 'una minuta',
|
||||
mm : '%d minutas',
|
||||
h : 'una ora',
|
||||
hh : '%d oras',
|
||||
d : 'un jorn',
|
||||
dd : '%d jorns',
|
||||
M : 'un mes',
|
||||
MM : '%d meses',
|
||||
y : 'un an',
|
||||
yy : '%d ans'
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}(r|n|t|è|a)/,
|
||||
ordinal : function (number, period) {
|
||||
var output = (number === 1) ? 'r' :
|
||||
(number === 2) ? 'n' :
|
||||
(number === 3) ? 'r' :
|
||||
(number === 4) ? 't' : 'è';
|
||||
if (period === 'w' || period === 'W') {
|
||||
output = 'a';
|
||||
}
|
||||
return number + output;
|
||||
},
|
||||
week : {
|
||||
dow : 1, // Monday is the first day of the week.
|
||||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||||
}
|
||||
});
|
@ -50,6 +50,7 @@
|
||||
"About": "Ajuda",
|
||||
"Settings": "Prefer\u00e9ncias",
|
||||
"exportGPX": "Exportar en GPX",
|
||||
"reportIssue": "Senhalar un probl\u00e8ma",
|
||||
"shareMapView": "Partejar la vista de la mapa"
|
||||
},
|
||||
"misc": {
|
||||
@ -68,6 +69,15 @@
|
||||
"preventSuspendDescription": "Quand la mapa es mostrada, lo periferic passar\u00e0 pas en velha.",
|
||||
"vibrate": "Vibracions"
|
||||
},
|
||||
"relativeDate": {
|
||||
"ago": "fa {duration}",
|
||||
"day": "un jorn | {count} jorns",
|
||||
"hour": "una ora | {count} oras",
|
||||
"minute": "una minuta | {count} minutas",
|
||||
"month": "un mes | {count} meses",
|
||||
"second": "unas segondas | {count} segondas",
|
||||
"year": "un an | {count} ans"
|
||||
},
|
||||
"reportCard": {
|
||||
"Reported": "Senhalat {fromNow}."
|
||||
},
|
||||
@ -75,6 +85,12 @@
|
||||
"unableToSendDescription": "Una error ret empacha lo mandad\u00eds del darri\u00e8r senhalament.",
|
||||
"unableToSendTitle": "Impossible d'enviar lo darri\u00e8r senhalament"
|
||||
},
|
||||
"reportIssueModal": {
|
||||
"description": "Descripcion",
|
||||
"includeGPX": "Inclure la tra\u00e7a GPS actuala\u00a0?",
|
||||
"reportIssue": "Senhalar un probl\u00e8ma",
|
||||
"send": "Enviar"
|
||||
},
|
||||
"reportLabels": {
|
||||
"accident": "Accident",
|
||||
"accidentDescription": "Un accident sus la rota (automaticament suprimit apr\u00e8p una ora).",
|
||||
@ -90,9 +106,12 @@
|
||||
"potholeDescription": "Un trauc per la rota."
|
||||
},
|
||||
"settings": {
|
||||
"autorotate": "Vira automaticament (direccion actuala amont)",
|
||||
"customTileServer": "Servidor de teulas personalizat",
|
||||
"customTileServerURL": "URL del servidor de teulas personalizat",
|
||||
"customTileServerURLHint": "Per exemple\u00a0: http://tile.thunderforest.com/cycle/{z}/{x}/{y}.png",
|
||||
"defaultOrientationMode": "M\u00f2de orientacion per defaut",
|
||||
"fixedNorth": "Fixada (N\u00f2rd amont)",
|
||||
"locale": "Lenga",
|
||||
"skipOnboarding": "Passar l'introduccion",
|
||||
"tileServer": "Servidor de teulas per la mapa"
|
||||
|
@ -1,5 +1,3 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import * as api from '@/api';
|
||||
import * as constants from '@/constants';
|
||||
import i18n from '@/i18n';
|
||||
@ -87,8 +85,6 @@ export function showReportDetails({ commit }, { id, userAsked }) {
|
||||
export function setLocale({ commit }, { locale }) {
|
||||
// Set global Vue-i18n locale
|
||||
i18n.locale = locale;
|
||||
// Set moment locale
|
||||
moment.locale(locale);
|
||||
// Commit setting into the store
|
||||
return commit(SET_SETTING, { setting: 'locale', value: locale });
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import moment from 'moment';
|
||||
import Vue from 'vue';
|
||||
|
||||
import { messages, getBrowserLocales } from '@/i18n';
|
||||
@ -80,8 +79,6 @@ if (storageAvailable('localStorage')) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set moment locale
|
||||
moment.locale(locale);
|
||||
}
|
||||
|
||||
export const initialState = {
|
||||
|
102
src/tools/date.js
Normal file
102
src/tools/date.js
Normal file
@ -0,0 +1,102 @@
|
||||
import i18n from '@/i18n';
|
||||
|
||||
/*
|
||||
* Code below is dapted from
|
||||
* https://github.com/date-fns/date-fns/blob/v1/src/format/index.js
|
||||
* Licensed under MIT © Sasha Koss.
|
||||
*/
|
||||
export function addLeadingZeros(number, targetLength) {
|
||||
let output = Math.abs(number).toString();
|
||||
while (output.length < targetLength) {
|
||||
output = `0${output}`;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const FORMATTERS = {
|
||||
// Month: 01, 02, ..., 12
|
||||
MM: date => addLeadingZeros(date.getMonth() + 1, 2),
|
||||
// Day of month: 01, 02, ..., 31
|
||||
DD: date => addLeadingZeros(date.getDate(), 2),
|
||||
// Year: 1900, 1901, ..., 2099
|
||||
YYYY: date => addLeadingZeros(date.getFullYear(), 4),
|
||||
// Hour: 00, 01, ..., 23
|
||||
HH: date => addLeadingZeros(date.getHours(), 2),
|
||||
// Minute: 00, 01, ..., 59
|
||||
mm: date => addLeadingZeros(date.getMinutes(), 2),
|
||||
// Day of the week: Mon, Tue, Wed, Thu, Fri, Sat, Sun
|
||||
ddd: date => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()],
|
||||
};
|
||||
|
||||
export function formatDate(date, format) {
|
||||
let output = format;
|
||||
Object.keys(FORMATTERS).forEach((formatter) => {
|
||||
output = output.replace(formatter, FORMATTERS[formatter](date));
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Code below is adapted from
|
||||
* https://github.com/yahoo/intl-relativeformat/blob/master/src/core.js
|
||||
* Copyright (c) 2014, Yahoo! Inc. All rights reserved.
|
||||
* Copyrights licensed under the New BSD License.
|
||||
*/
|
||||
|
||||
const THRESHOLDS = {
|
||||
second: 45,
|
||||
minute: 45,
|
||||
hour: 22,
|
||||
day: 26,
|
||||
month: 11,
|
||||
};
|
||||
|
||||
function daysToYears(days) {
|
||||
// 400 years have 146097 days (taking into account leap year rules)
|
||||
return days * 400 / 146097;
|
||||
}
|
||||
|
||||
export function diff(from, to) {
|
||||
// Convert to ms timestamps.
|
||||
const millisecond = Math.round(+to - (+from));
|
||||
const second = Math.round(millisecond / 1000);
|
||||
const minute = Math.round(second / 60);
|
||||
const hour = Math.round(minute / 60);
|
||||
const day = Math.round(hour / 24);
|
||||
const week = Math.round(day / 7);
|
||||
|
||||
const rawYears = daysToYears(day);
|
||||
const month = Math.round(rawYears * 12);
|
||||
const year = Math.round(rawYears);
|
||||
|
||||
return {
|
||||
millisecond,
|
||||
second,
|
||||
minute,
|
||||
hour,
|
||||
day,
|
||||
week,
|
||||
month,
|
||||
year,
|
||||
};
|
||||
}
|
||||
|
||||
export function selectUnits(diffReport) {
|
||||
const fields = Object.keys(THRESHOLDS);
|
||||
for (let i = 0; i < fields.length; i += 1) {
|
||||
const units = fields[i];
|
||||
if (Math.abs(diffReport[units]) < THRESHOLDS[units]) {
|
||||
return units;
|
||||
}
|
||||
}
|
||||
return 'year';
|
||||
}
|
||||
|
||||
export function distanceInWordsToNow(from) {
|
||||
const diffReport = diff(from, new Date());
|
||||
const units = selectUnits(diffReport);
|
||||
const diffInUnits = Math.abs(diffReport[units]);
|
||||
return i18n.t('relativeDate.ago', {
|
||||
duration: i18n.tc(`relativeDate.${units}`, diffInUnits, { count: diffInUnits }),
|
||||
});
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import FileSaver from 'file-saver';
|
||||
import createGPX from 'gps-to-gpx';
|
||||
import moment from 'moment';
|
||||
|
||||
import { VERSION } from '@/constants';
|
||||
import { formatDate } from '@/tools/date';
|
||||
|
||||
export default function (activityName, locationGPX) {
|
||||
const courseKey = 'heading';
|
||||
@ -36,6 +36,6 @@ export default function (activityName, locationGPX) {
|
||||
});
|
||||
FileSaver.saveAs(
|
||||
new Blob([gpx], { type: 'application/gpx+xml;charset=utf-8' }),
|
||||
`cyclassist_${moment().locale('en').format('YYYY-MM-DD_HH-mm_ddd')}.gpx`,
|
||||
`cyclassist_${formatDate(new Date(), 'YYYY-MM-DD_HH-mm_ddd')}.gpx`,
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
EARTH_RADIUS,
|
||||
@ -61,8 +60,8 @@ export function mockLocationWithGPX(index, setPosition) {
|
||||
setPosition(mockGPX[index]);
|
||||
if (mockGPX[index + 1]) {
|
||||
const delay = (
|
||||
moment(mockGPX[index + 1].time).valueOf()
|
||||
- moment(mockGPX[index].time).valueOf()
|
||||
Date.parse(mockGPX[index + 1].time).getTime()
|
||||
- Date.parse(mockGPX[index].time).getTime()
|
||||
);
|
||||
setTimeout(
|
||||
() => mockLocationWithGPX(index + 1, setPosition),
|
||||
|
@ -26,9 +26,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
|
||||
import { getStats } from '@/api';
|
||||
import { distanceInWordsToNow } from '@/tools/date';
|
||||
|
||||
import ReportsDescription from '@/components/ReportsDescription.vue';
|
||||
|
||||
@ -49,7 +48,7 @@ export default {
|
||||
getStats().then((stats) => {
|
||||
this.stats = stats;
|
||||
this.stats.last_added_report_datetime = (
|
||||
moment(this.stats.last_added_report_datetime).fromNow()
|
||||
distanceInWordsToNow(Date.parse(this.stats.last_added_report_datetime))
|
||||
);
|
||||
});
|
||||
},
|
||||
|
@ -124,8 +124,14 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const $t = this.$t.bind(this);
|
||||
const i18nItems = [];
|
||||
Object.keys(AVAILABLE_LOCALES).forEach(iso => i18nItems.push({
|
||||
iso,
|
||||
name: AVAILABLE_LOCALES[iso].name,
|
||||
}));
|
||||
i18nItems.sort((a, b) => a.iso > b.iso);
|
||||
return {
|
||||
i18nItems: AVAILABLE_LOCALES,
|
||||
i18nItems,
|
||||
orientationModes: [
|
||||
{
|
||||
text: $t('settings.fixedNorth'),
|
||||
|
@ -5980,10 +5980,6 @@ mkpath@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-0.1.0.tgz#7554a6f8d871834cc97b5462b122c4c124d6de91"
|
||||
|
||||
moment@^2.22.2:
|
||||
version "2.22.2"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
|
||||
|
||||
mout@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501"
|
||||
|
Loading…
Reference in New Issue
Block a user