Add translations for relative times

This commit is contained in:
Matt Isenhower
2017-12-04 15:34:00 -08:00
parent 0684e434f4
commit cf9c9da3ff
14 changed files with 263 additions and 53 deletions

View File

@@ -86,7 +86,7 @@
</span>
</span>
<span class="is-size-7 is-hidden-touch is-pulled-right">
in {{ event.start_time - now | duration(true) }}
{{ event.start_time - now | duration(true) | timeIn }}
</span>
</div>
</div>
@@ -108,6 +108,7 @@
</template>
<script>
import Vue from 'vue';
import SalmonRunDetailsBar from './SalmonRunDetailsBar.vue';
import SalmonRunGearDialog from './SalmonRunGearDialog.vue';
@@ -119,6 +120,11 @@ export default {
gearDialogOpen: false,
};
},
filters: {
timeIn(time) {
return Vue.i18n.translate('time.in', { time });
},
},
computed: {
allSchedules() {
// Combine the "schedules" and "details" sections into one list of schedules

View File

@@ -8,7 +8,7 @@
<div class="level-item has-text-right">
<div>
<template v-if="schedule.start_time > now">
in {{ schedule.start_time - now | duration }}<span class="is-hidden-mobile">,&nbsp;</span>
{{ timeFromNow }}<span class="is-hidden-mobile">,&nbsp;</span>
</template>
<div class="is-size-7">
{{ schedule.start_time | time }} &ndash;
@@ -24,7 +24,7 @@
<div class="title is-size-5-fullhd is-size-5-touch" :class="ruleNameClass">{{ ruleName }}</div>
<div class="subtitle is-size-6-fullhd is-size-6-touch" :class="scheduleClass">
<template v-if="schedule.start_time > now">
in {{ schedule.start_time - now | duration }}
{{ timeFromNow }}
<br />
</template>
<template v-if="!isToday">
@@ -46,6 +46,7 @@
</template>
<script>
import Vue from 'vue';
import Stage from './Stage.vue';
export default {
@@ -63,6 +64,10 @@ export default {
},
ruleNameClass() { return this.smallSize ? 'is-6' : 'is-5' },
scheduleClass() { return this.smallSize ? 'is-7' : 'is-6' },
timeFromNow() {
let time = Vue.filter('duration')(this.schedule.start_time - this.now);
return this.$t('time.in', { time });
},
}
}
</script>

View File

@@ -43,28 +43,18 @@
</div>
<div class="splatfest-content has-text-centered" v-if="!screenshotMode">
<template v-if="state == 'upcoming'">
in
{{ festival.times.start - now | duration }}
</template>
<template v-else-if="state == 'active'">
{{ festival.times.end - now | duration }}
remaining
<template v-if="state == 'upcoming' || state == 'active'">
{{ formattedDuration }}
</template>
<template v-else-if="state == 'past' && !results && festival.times.result > now">
results in
{{ festival.times.result - now | duration }}
{{ resultsIn }}
</template>
</div>
<div class="has-text-centered is-size-5 title-color festival-period-container" v-if="screenshotMode">
<div class="festival-period" :style="{ 'background-color': festival.colors.middle.css_rgb }" v-if="state == 'upcoming'">
in {{ festival.times.start - now | shortDuration }}
</div>
<div class="festival-period" :style="{ 'background-color': festival.colors.middle.css_rgb }" v-else-if="state == 'active'">
{{ festival.times.end - now | durationHours }} remaining
<div class="festival-period" :style="{ 'background-color': festival.colors.middle.css_rgb }" v-if="state == 'upcoming' || state == 'active'">
{{ screenshotModeDuration }}
</div>
<div v-else>&nbsp;</div>
</div>
@@ -97,6 +87,34 @@ export default {
if (this.festival)
return Vue.filter('localSplatNetImageUrl')(this.festival.images.panel);
},
formattedDuration() {
let time;
switch (this.state) {
case 'upcoming':
time = Vue.filter('duration')(this.festival.times.start - this.now);
return this.$t('time.in', { time });
case 'active':
time = Vue.filter('duration')(this.festival.times.end - this.now);
return this.$t('time.remaining', { time });
}
},
resultsIn() {
let time = Vue.filter('duration')(this.festival.times.result - this.now);
return this.$t('splatfest.results_in', { time });
},
screenshotModeDuration() {
let time;
switch (this.state) {
case 'upcoming':
time = Vue.filter('shortDuration')(this.festival.times.start - this.now);
return this.$t('time.in', { time });
case 'active':
time = Vue.filter('durationHours')(this.festival.times.end - this.now);
return this.$t('time.remaining', { time });
}
},
}
}
</script>

View File

@@ -1,4 +1,5 @@
import Vue from 'vue';
const $t = Vue.i18n.translate;
// Local hosting of SplatNet images
Vue.filter('localSplatNetImageUrl', function(value) {
@@ -42,34 +43,34 @@ Vue.filter('duration', function(value, hideSeconds = false) {
minutes = ('0' + minutes).substr(-2);
seconds = ('0' + seconds).substr(-2);
if (days) {
if (hideSeconds)
return `${negative}${days}d ${hours}h ${minutes}m`;
return `${negative}${days}d ${hours}h ${minutes}m ${seconds}s`;
}
if (hours) {
if (hideSeconds)
return `${negative}${hours}h ${minutes}m`;
return `${negative}${hours}h ${minutes}m ${seconds}s`;
}
return `${negative}${minutes}m ${seconds}s`;
// Format for translation
days = days && $t('time.daysShort', { days }, parseInt(days));
hours = hours && $t('time.hoursShort', { hours }, parseInt(hours));
minutes = $t('time.minutesShort', { minutes }, parseInt(minutes));
seconds = $t('time.secondsShort', { seconds }, parseInt(seconds));
if (days)
return negative + $t((hideSeconds) ? 'time.dhm' : 'time.dhms', { days, hours, minutes, seconds });
if (hours)
return negative + $t((hideSeconds) ? 'time.hm' : 'time.hms', { hours, minutes, seconds });
return negative + $t('time.ms', { minutes, seconds });
});
Vue.filter('shortDuration', function (value) {
let { negative, days, hours, minutes, seconds } = getDurationParts(value);
if (days)
return (days == 1) ? `${negative}1 day` : `${negative}${days} days`;
return $t('time.days', { days: negative + days }, days);
if (hours)
return (hours == 1) ? `${negative}1 hour` : `${negative}${hours} hours`;
return $t('time.hours', { hours: negative + hours }, hours);
if (minutes)
return (minutes == 1) ? `${negative}1 minute` : `${negative}${minutes} minutes`;
return (seconds == 1) ? `${negative}1 second` : `${negative}${seconds} seconds`;
return $t('time.minutes', { minutes: negative + minutes }, minutes);
return $t('time.seconds', { seconds: negative + seconds }, seconds);
});
Vue.filter('durationHours', function (value) {
let { negative, days, hours, minutes, seconds } = getDurationParts(value);
hours += 24 * days;
return (hours == 1) ? `${negative}1 hour` : `${negative}${hours} hours`;
return $t('time.hours', { hours: negative + hours }, hours);
});

View File

@@ -24,7 +24,8 @@
"battle": "Splatfestkämpfe",
"recent": "Splatfest",
"title": "Splatfest",
"upcoming": "Splatfest"
"upcoming": "Splatfest",
"results_in": "Ergebnisse in {time}"
},
"splatnet_gear": {
"button": "TentaWorld",
@@ -35,5 +36,22 @@
"next": "Demnächst",
"now": "Jetzt",
"soon": "Demnächst"
},
"time": {
"in": "in {time}",
"remaining": "Noch {time}",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} Sekunde ::: {seconds} Sekunden",
"minutes": "{minutes} Minute ::: {minutes} Minuten",
"hours": "{hours} Stunde ::: {hours} Stunden",
"days": "{days} Tag ::: {days} Tage",
"secondsShort": "{seconds}Sek ::: {seconds}Sek",
"minutesShort": "{minutes}Min ::: {minutes}Min",
"hoursShort": "{hours}Std ::: {hours}Std",
"daysShort": "{days}Tg ::: {days}Tg"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Splatfest Battle",
"recent": "Recent Splatfest",
"title": "Splatfest",
"upcoming": "Upcoming Splatfest"
"upcoming": "Upcoming Splatfest",
"results_in": "results in {time}"
},
"splatnet_gear": {
"button": "SplatNet Gear",
@@ -35,5 +36,22 @@
"next": "Next",
"now": "Now",
"soon": "Soon!"
},
"time": {
"in": "in {time}",
"remaining": "{time} remaining",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} second ::: {seconds} seconds",
"minutes": "{minutes} minute ::: {minutes} minutes",
"hours": "{hours} hour ::: {hours} hours",
"days": "{days} day ::: {days} days",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}h ::: {hours}h",
"daysShort": "{days}d ::: {days}d"
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Festival del Teñido",
"recent": "Festival",
"title": "Festival",
"upcoming": "Festival"
"upcoming": "Festival",
"results_in": "resultados en {time}"
},
"splatnet_gear": {
"button": "Tienda SplatNet",
@@ -35,5 +36,22 @@
"next": "Próximo",
"now": "Ahora",
"soon": "Siguiente"
},
"time": {
"in": "en {time}",
"remaining": "{time} restante",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} segundo ::: {seconds} segundos",
"minutes": "{minutes} minuto ::: {minutes} minutos",
"hours": "{hours} hora ::: {hours} horas",
"days": "{days} día ::: {days} días",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}h ::: {hours}h",
"daysShort": "{days}d ::: {days}d"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Combates temáticos",
"recent": "Festival",
"title": "Festival",
"upcoming": "Festival"
"upcoming": "Festival",
"results_in": "resultados en {time}"
},
"splatnet_gear": {
"button": "Tentatienda",
@@ -35,5 +36,22 @@
"next": "Próximos",
"now": "Ahora",
"soon": "Próximo"
},
"time": {
"in": "en {time}",
"remaining": "{time} restante",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} segundo ::: {seconds} segundos",
"minutes": "{minutes} minuto ::: {minutes} minutos",
"hours": "{hours} hora ::: {hours} horas",
"days": "{days} día ::: {days} días",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}h ::: {hours}h",
"daysShort": "{days}d ::: {days}d"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Festimatch",
"recent": "Festival",
"title": "Festival",
"upcoming": "Festival"
"upcoming": "Festival",
"results_in": "résultats en {time}"
},
"splatnet_gear": {
"button": "Boutique SplatNet",
@@ -35,5 +36,22 @@
"next": "Suivants",
"now": "À présent",
"soon": "Bientôt!"
},
"time": {
"in": "dans {time}",
"remaining": "{time} restants",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} seconde ::: {seconds} secondes",
"minutes": "{minutes} minute ::: {minutes} minutes",
"hours": "{hours} heure ::: {hours} heures",
"days": "{days} jour ::: {days} jours",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}h ::: {hours}h",
"daysShort": "{days}j ::: {days}j"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Festimatchs",
"recent": "Festival",
"title": "Festival",
"upcoming": "Festival"
"upcoming": "Festival",
"results_in": "résultats en {time}"
},
"splatnet_gear": {
"button": "Céphalochic",
@@ -35,5 +36,22 @@
"next": "Suivants",
"now": "À présent",
"soon": "Bientôt !"
},
"time": {
"in": "dans {time}",
"remaining": "{time} restants",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} seconde ::: {seconds} secondes",
"minutes": "{minutes} minute ::: {minutes} minutes",
"hours": "{hours} heure ::: {hours} heures",
"days": "{days} jour ::: {days} jours",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}h ::: {hours}h",
"daysShort": "{days}j ::: {days}j"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Partite tematiche",
"recent": "Festival",
"title": "Festival",
"upcoming": "Festival"
"upcoming": "Festival",
"results_in": "risultati in {time}"
},
"splatnet_gear": {
"button": "Calama-zone",
@@ -35,5 +36,22 @@
"next": "Prossimi",
"now": "Adesso",
"soon": "Presto!"
},
"time": {
"in": "tra {time}",
"remaining": "{time} rimanenti",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} secondo ::: {seconds} secondi",
"minutes": "{minutes} minuto ::: {minutes} minuti",
"hours": "{hours} ora ::: {hours} ore",
"days": "{days} giorno ::: {days} giorni",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}o ::: {hours}o",
"daysShort": "{days}g ::: {days}g"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "フェスマッチ",
"recent": "フェス",
"title": "フェス",
"upcoming": "フェス"
"upcoming": "フェス",
"results_in": "結果発表 {time}"
},
"splatnet_gear": {
"button": "ゲソタウン",
@@ -35,5 +36,22 @@
"next": "つぎ",
"now": "今",
"soon": "もうすぐ"
},
"time": {
"in": "{time}後",
"remaining": "残り{time}",
"dhm": "{days}{hours}{minutes}",
"dhms": "{days}{hours}{minutes}{seconds}",
"hm": "{hours}{minutes}",
"hms": "{hours}{minutes}{seconds}",
"ms": "{minutes}{seconds}",
"seconds": "{seconds}秒 ::: {seconds}秒",
"minutes": "{minutes}分 ::: {minutes}分",
"hours": "{hours}時間 ::: {hours}時間",
"days": "{days}日 ::: {days}日",
"secondsShort": "{seconds}秒 ::: {seconds}秒",
"minutesShort": "{minutes}分 ::: {minutes}分",
"hoursShort": "{hours}時間 ::: {hours}時間",
"daysShort": "{days}日 ::: {days}日"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Splatfest-gevecht",
"recent": "Splatfest",
"title": "Splatfest",
"upcoming": "Splatfest"
"upcoming": "Splatfest",
"results_in": "resultaten in {time}"
},
"splatnet_gear": {
"button": "Tentashop",
@@ -35,5 +36,22 @@
"next": "Volgende",
"now": "Nu",
"soon": "Binnenkort!"
},
"time": {
"in": "over {time}",
"remaining": "Nog {time}",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} seconde ::: {seconds} seconden",
"minutes": "{minutes} minuut ::: {minutes} minuten",
"hours": "{hours} uur ::: {hours} uur",
"days": "{days} dag ::: {days} dagen",
"secondsShort": "{seconds}s ::: {seconds}s",
"minutesShort": "{minutes}m ::: {minutes}m",
"hoursShort": "{hours}u ::: {hours}u",
"daysShort": "{days}d ::: {days}d"
}
}
}

View File

@@ -24,7 +24,8 @@
"battle": "Сплатфест-бой",
"recent": "Сплатфест",
"title": "Сплатфест",
"upcoming": "Сплатфест"
"upcoming": "Сплатфест",
"results_in": "результаты за {time}"
},
"splatnet_gear": {
"button": "«Щупозон»",
@@ -35,5 +36,22 @@
"next": "Далее",
"now": "Теперь",
"soon": "Далее"
},
"time": {
"in": "через {time}",
"remaining": "Осталось: {time}",
"dhm": "{days} {hours} {minutes}",
"dhms": "{days} {hours} {minutes} {seconds}",
"hm": "{hours} {minutes}",
"hms": "{hours} {minutes} {seconds}",
"ms": "{minutes} {seconds}",
"seconds": "{seconds} секунда ::: {seconds} секунды",
"minutes": "{minutes} минута ::: {minutes} минута",
"hours": "{hours} час ::: {hours} часа",
"days": "{days} день ::: {days} дня",
"secondsShort": "{seconds} секунда ::: {seconds} секунды",
"minutesShort": "{minutes} минута ::: {minutes} минута",
"hoursShort": "{hours} час ::: {hours} часа",
"daysShort": "{days} день ::: {days} дня"
}
}
}