Skip to content

Commit

Permalink
feat: add i18n and french lang
Browse files Browse the repository at this point in the history
  • Loading branch information
Toinane committed Oct 7, 2022
1 parent 212f05c commit 8c5c534
Show file tree
Hide file tree
Showing 25 changed files with 757 additions and 195 deletions.
475 changes: 406 additions & 69 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"warmCaches": "node app/index.mjs warmCaches"
},
"dependencies": {
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
"console-stamp": "^3.0.6",
"cron": "^2.1.0",
"dotenv": "^16.0.2",
Expand All @@ -24,6 +25,7 @@
"puppeteer": "^18.0.3",
"twitter-api-v2": "^1.12.7",
"vue": "^3.2.39",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.5"
},
"devDependencies": {
Expand Down
96 changes: 96 additions & 0 deletions src/assets/i18n/en-US.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"locales": {
"en-US": "🇺🇸 English",
"fr-FR": "🇫🇷 Français"
},
"time": {
"in": "in",
"now": "Now Open!",
"next": "Next",
"soon": "Soon!",
"remaining": "remaining",
"until": "Until",
"left": "left",
"checkback": "Check back soon!",
"d": "d",
"day": "day",
"days": "days",
"h": "h",
"hour": "hour",
"hours": "hours",
"m": "m",
"minute": "minute",
"minutes": "minutes",
"s": "s",
"second": "second",
"seconds": "seconds"
},
"maps": {
"Scorch Gorge": "Scorch Gorge",
"Wahoo World": "Wahoo World",
"Hagglefish Market": "Hagglefish Market",
"Undertow Spillway": "Undertow Spillway",
"MakoMart": "MakoMart",
"Museum dAlfonsino": "Museum d'Alfonsino",
"Sturgeon Shipyard": "Sturgeon Shipyard",
"Mincemeat Metalworks": "Mincemeat Metalworks",
"Mahi-Mahi Resort": "Mahi-Mahi Resort",
"Hammerhead Bridge": "Hammerhead Bridge",
"Eeltail Alley": "Eeltail Alley",
"Inkblot Art Academy": "Inkblot Art Academy",
"Spawning Grounds": "Spawning Grounds",
"Sockeye Station": "Sockeye Station",
"Gone Fission Hydroplant": "Gone Fission Hydroplant"
},
"schedule": {
"title": "Map Schedules",
"subtitle": "Schedules",
"modes": {
"Turf War": "Turf War",
"Rainmaker": "Rainmaker",
"Splat Zones": "Splat Zones",
"Clam Blitz": "Clam Blitz",
"Tower Control": "Tower Control"
},
"types": {
"Series": "Series",
"Open": "Open",
"Regular Battle": "Regular Battle",
"Anarchy Battle": "Anarchy Battle",
"Splatfest Battle": "Splatfest Battle"
}
},
"salmonrun": {
"title": "Salmon Run",
"weapons": "Supplied Weapons"
},
"gear": {
"title": "Gear",
"sale": "Gear on Sale Now",
"splatnet-gear": "SplatNet Gear",
"dailydrop": "The Daily Drop",
"order": "Order"
},
"about": {
"title": "About!",
"subtitle-1": "What is this?",
"text-1": "This site is a fan-made, unofficial source of information for Nintendo's Splatoon 3. You might remember me from {0}!",
"subtitle-2": "How was this site made?",
"text-2": "On the front end, this site was built with {0}, {1}, and {2}. Static assets are compiled using {3}.",
"text-3": "On the back end, the data updaters and Twitter bot were written using {0}. Special thanks to the {1} and {2} projects for their work to make automated Nintendo Switch Online logins possible.",
"text-4": "The Twitter bot at {0} uses {1} to automatically generate images for each tweet.",
"text-5": "This site is completely open source. You can view the source here on {0}.",
"subtitle-3": "Can I use data from this site in my own project?",
"text-6": "Yes! I love seeing all the creative projects people come up with that use this site's data.",
"text-7": "Please see the {0} page for a list of all available endpoints.",
"subtitle-4": "How can I reach you?",
"text-8": "Please feel free to contact me on Twitter at {0} or via {1} if you have any other questions!",
"email": "email",
"schedules": "Splatoon 3 Schedules"
},
"footer": {
"term": "This website is not affiliated with Nintendo. All product names, logos, and brands are property of their respective owners.",
"about": "About",
"data": "Data"
}
}
92 changes: 92 additions & 0 deletions src/assets/i18n/fr-FR.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"time": {
"in": "dans",
"next": "Suivant",
"now": "En cours !",
"soon": "Prochains !",
"remaining": "restant",
"until": "Jusqu'au",
"left": "restantes",
"checkback": "Revenez voir plus tard !",
"d": "j",
"day": "jour",
"days": "jours",
"h": "h",
"hour": "heure",
"hours": "heures",
"m": "m",
"minute": "minute",
"minutes": "minutes",
"s": "s",
"second": "seconde",
"seconds": "secondes"
},
"maps": {
"Scorch Gorge": "Canyon aux colonnes",
"Wahoo World": "Parc Carapince",
"Hagglefish Market": "Marché Grefin",
"Undertow Spillway": "Réservoir Rigadelle",
"MakoMart": "Supermarché Cétacé",
"Museum dAlfonsino": "Galeries Guppy",
"Sturgeon Shipyard": "Chantier Narval",
"Mincemeat Metalworks": "Casse Rascasse",
"Mahi-Mahi Resort": "Club Ca$halot",
"Hammerhead Bridge": "Pont Esturgeon",
"Eeltail Alley": "Banlieu Balibot",
"Inkblot Art Academy": "Institut Calam'arts",
"Spawning Grounds": "Barrage samonoïde",
"Sockeye Station": "Bastion colimaçon",
"Gone Fission Hydroplant": "Centrale Anguilla"
},
"schedule": {
"title": "Planning",
"subtitle": "Planning",
"modes": {
"Turf War": "Guerre de territoire",
"Rainmaker": "Mission Bazookarpe",
"Splat Zones": "Défense de zone",
"Clam Blitz": "Pluie de palourde",
"Tower Control": "Expédition risquée"
},
"types": {
"Series": "Série",
"Open": "Ouvert",
"Regular Battle": "Match Classique",
"Anarchy Battle": "Match Anarchie",
"Splatfest Battle": "Match Splatfest"
}
},
"salmonrun": {
"title": "Salmon Run",
"weapons": "Armes fournies"
},
"gear": {
"title": "Équipement",
"sale": "Équipement en solde",
"splatnet-gear": "Équipement SplatNet",
"dailydrop": "Chouchou du jour",
"order": "Acheter"
},
"about": {
"title": "À propos !",
"subtitle-1": "Qu'est-ce que c'est ?",
"text-1": "Ce site est une source d'informations non officielle, créée par un fan, sur le jeu Splatoon 3 de Nintendo. Vous vous souvenez peut-être de moi pour {0}!",
"subtitle-2": "Comment ce site a-t-il été créé ?",
"text-2": "Côté front, ce site a été conçu avec {0}, {1} et {2}. Les ressources statiques sont compilées en utilisant {3}.",
"text-3": "Côté back, les modules de mise à jour des données et le bot Twitter ont été développés à l'aide de {0}. Remerciements spécials pour les projets {1} et {2} pour leur travail visant à rendre possible la connexion automatique au Nintendo Switch Online.",
"text-4": "Le bot Twitter {0} utilise {1} pour générer automatiquement des images pour chaque tweet.",
"text-5": "Ce site est entièrement open source. Vous pouvez consulter les sources ici sur {0}.",
"subtitle-3": "Puis-je utiliser les données de ce site dans mon propre projet ?",
"text-6": "Oui ! J'adore voir tous les projets créatifs que les gens imaginent en utilisant les données de ce site.",
"text-7": "Veuillez consulter la page {0} pour obtenir une liste de tous les endpoints.",
"subtitle-4": "Comment puis-je vous contacter ?",
"text-8": "N'hésitez pas à me contacter sur Twitter à {0} ou via {1} si vous avez d'autres questions !",
"email": "email",
"schedules": "Planning Splatoon 3"
},
"footer": {
"term": "Ce site internet n'est pas affilié à Nintendo. Tous les noms de produits, logos et marques sont la propriété de leurs détenteurs respectifs.",
"about": "À propos",
"data": "Données"
}
}
7 changes: 7 additions & 0 deletions src/assets/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import en_us from './en-US.json'
import fr_fr from './fr-FR.json'

export default {
"en-US": en_us,
"fr-FR": fr_fr
}
34 changes: 19 additions & 15 deletions src/common/time.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useI18n } from 'vue-i18n';
import { useTimeStore } from '../stores/time';

export function formatDateTime(value) {
Expand Down Expand Up @@ -26,23 +27,24 @@ function getDurationParts(value) {
// Countdown duration (e.g., 1d 13h 21m 19s)
// "hideSeconds" only hides seconds when the time is >= 1 hour, this is used in the Salmon Run box
export function formatDuration(value, hideSeconds = false) {
const i18n = useI18n()
let { negative, days, hours, minutes, seconds } = getDurationParts(value);

// Add leading zeros
if (days || hours)
minutes = ('0' + minutes).substr(-2);
minutes = ('0' + minutes).substr(-2);
seconds = ('0' + seconds).substr(-2);

// Format for translation
days = days && `${days}d`;
hours = (days || hours) && `${hours}h`;
minutes = `${minutes}m`;
seconds = `${seconds}s`;
days = days && `${days}${i18n.t('time.d')}`;
hours = (days || hours) && `${hours}${i18n.t('time.h')}`;
minutes = `${minutes}${i18n.t('time.m')}`;
seconds = `${seconds}${i18n.t('time.s')}`;

if (days)
return negative + (hideSeconds ? `${days} ${hours} ${minutes}` : `${days} ${hours} ${minutes} ${seconds}`);
return negative + (hideSeconds ? `${days} ${hours} ${minutes}` : `${days} ${hours} ${minutes} ${seconds}`);
if (hours)
return negative + (hideSeconds ? `${hours} ${minutes}` : `${hours} ${minutes} ${seconds}`);
return negative + (hideSeconds ? `${hours} ${minutes}` : `${hours} ${minutes} ${seconds}`);
return negative + `${minutes} ${seconds}`;
}

Expand All @@ -53,15 +55,16 @@ export function formatDurationFromNow(value, hideSeconds = false) {
}

export function formatShortDuration(value) {
const i18n = useI18n()
let { negative, days, hours, minutes, seconds } = getDurationParts(value);

if (days)
return `${negative}${days} ${days === 1 ? 'day' : 'days'}`;
if (hours)
return `${negative}${hours} ${hours === 1 ? 'hour' : 'hours'}`;
if (minutes)
return `${negative}${minutes} ${minutes === 1 ? 'minute' : 'minutes'}`;
return `${negative}${seconds} ${seconds === 1 ? 'second' : 'seconds'}`;
if (days)
return `${negative}${days} ${days === 1 ? i18n.t('time.day') : i18n.t('time.days')}`;
if (hours)
return `${negative}${hours} ${hours === 1 ? i18n.t('time.hour') : i18n.t('time.hours')}`;
if (minutes)
return `${negative}${minutes} ${minutes === 1 ? i18n.t('time.minute') : i18n.t('time.minutes')}`;
return `${negative}${seconds} ${seconds === 1 ? i18n.t('time.second') : i18n.t('time.seconds')}`;
}

export function formatShortDurationFromNow(value) {
Expand All @@ -71,11 +74,12 @@ export function formatShortDurationFromNow(value) {
}

export function formatDurationHours(value) {
const i18n = useI18n()
let { negative, days, hours } = getDurationParts(value);

hours += 24 * days;

return `${negative}${hours} ${hours === 1 ? 'hour' : 'hours'}`;
return `${negative}${hours} ${hours === 1 ? i18n.t('time.hour') : i18n.t('time.hours')}`;
}

export function formatDurationHoursFromNow(value) {
Expand Down
29 changes: 29 additions & 0 deletions src/components/LanguageButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<select @change="onLanguageChange" v-model="$i18n.locale" class="language font-splatoon2 md:absolute md:mb-0 mb-5">
<option v-for="locale in $i18n.availableLocales" :key="`locale-${locale}`" :value="locale">{{ $t('locales.' + locale) }}</option>
</select>
</template>

<script setup>
import { useI18n } from "vue-i18n"
const i18n = useI18n()
const onLanguageChange = () => {
localStorage.setItem('lang', i18n.locale.value)
}
</script>

<style scoped>
.language {
right: 2.5vw;
@apply text-zinc-300 pl-4 py-1 bg-zinc-300 bg-opacity-20 rounded-full cursor-pointer
}
.language:hover {
@apply text-zinc-50 bg-opacity-30;
}
.language option {
@apply text-black
}
</style>
6 changes: 3 additions & 3 deletions src/components/NavButtons.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template>
<div class="flex font-splatoon2 space-x-2">
<router-link to="/" class="router-link">
Schedules
{{ $t('schedule.subtitle') }}
</router-link>
<router-link to="/salmonrun" class="router-link">
Salmon Run
{{ $t('salmonrun.title') }}
</router-link>
<router-link to="/gear" class="router-link">
Gear
{{ $t('gear.title') }}
</router-link>
</div>
</template>
Expand Down
8 changes: 4 additions & 4 deletions src/components/ScheduleBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<div class="flex items-center space-x-2 mx-2">
<img :src="type.img" />
<div class="font-splatoon1 lg:text-2xl xl:text-3xl text-shadow">
{{ type.name }}
{{ $t('schedule.types.' + type.name) }}
</div>
<div v-if="type.badge" class="font-splatoon2 text-xs lg:text-sm xl:text-base bg-splatoon-blue rounded px-1 drop-shadow">
{{ type.badge }}
{{ $t('schedule.types.' + type.badge) }}
</div>
</div>

Expand All @@ -18,7 +18,7 @@
<div>
<RuleIcon :rule="store.activeSchedule.settings.vsRule" class="h-5 lg:h-6" />
</div>
<div class="text-shadow">{{ store.activeSchedule.settings.vsRule.name }}</div>
<div class="text-shadow">{{ $t('schedule.modes.' + store.activeSchedule.settings.vsRule.name) }}</div>
</template>

<template v-else>
Expand Down Expand Up @@ -62,7 +62,7 @@

<div class="mx-2 space-y-2" v-if="nextSchedule && nextSchedule.settings">
<SquidTape class="font-splatoon2 text-sm drop-shadow -rotate-6 -mx-2">
<div class="px-2">Next</div>
<div class="px-2">{{ $t('time.next') }}</div>
</SquidTape>

<ScheduleRow :schedule="nextSchedule" />
Expand Down
4 changes: 2 additions & 2 deletions src/components/ScheduleRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
<RuleIcon :rule="props.schedule.settings.vsRule" class="h-5 lg:h-6" />
</div>
<div class="text-xs lg:text-lg text-shadow">
{{ props.schedule.settings.vsRule.name }}
{{ $t('schedule.modes.' + props.schedule.settings.vsRule.name) }}
</div>
</div>

<div class="text-sm text-zinc-300 text-shadow">
in {{ formatDurationFromNow(props.schedule.startTime) }}
{{ $t('time.in') }} {{ formatDurationFromNow(props.schedule.startTime) }}
</div>

<div class="text-sm text-zinc-300 text-shadow">
Expand Down
2 changes: 1 addition & 1 deletion src/components/StageImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
whitespace-nowrap
font-splatoon2
px-2
" :class="textSize" v-if="!hideLabel">{{ stage?.name }}</div>
" :class="textSize" v-if="!hideLabel">{{ $t('maps.' + stage?.name.replace("'", '')) }}</div>
</div>
</template>

Expand Down
Loading

0 comments on commit 8c5c534

Please sign in to comment.