diff --git a/.env.example b/.env.example index 992a94e..5f3e191 100644 --- a/.env.example +++ b/.env.example @@ -17,4 +17,7 @@ NUXT_DISCORD_TOKEN= NUXT_DISCORD_USER_ID= # Cloud files -NUXT_PUBLIC_CLOUD_RESUME= \ No newline at end of file +NUXT_PUBLIC_CLOUD_RESUME= + +# Nuxt I18N +NUXT_PUBLIC_I18N_BASE_URL= \ No newline at end of file diff --git a/README.md b/README.md index 94848ed..c01b81f 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ NUXT_DISCORD_USER_ID=... # Cloud files NUXT_PUBLIC_CLOUD_RESUME=... + +# Nuxt I18N +NUXT_PUBLIC_I18N_BASE_URL=... ``` ## 📄 License diff --git a/app/components/AppFooter.vue b/app/components/AppFooter.vue index e25a720..3436efc 100644 --- a/app/components/AppFooter.vue +++ b/app/components/AppFooter.vue @@ -20,6 +20,10 @@ const socials = [ link: 'https://discordapp.com/users/179635349100691456' } ] + +const { t } = useI18n({ + useScope: 'local' +}) + + +{ + "en": { + "find": "Find me on:", + "email": "Or send me an email:", + "copyright": "© {date} Arthur Danjou. All rights reserved." + }, + "fr": { + "find": "Retrouvez-moi sur :", + "email": "Ou envoyez-moi un email :", + "copyright": "© {date} Arthur Danjou. Tous droits réservés." + } +} + diff --git a/app/components/AppHeader.vue b/app/components/AppHeader.vue index 3ef2aaf..be59657 100644 --- a/app/components/AppHeader.vue +++ b/app/components/AppHeader.vue @@ -8,67 +8,109 @@ watch(isDark, () => { const config = useRuntimeConfig() const navs = [ { - label: 'home', + label: { + en: 'home', + fr: 'accueil' + }, to: '/', icon: 'i-ph-house-line-duotone', - shortcut: 'h' + shortcut: { + en: 'h', + fr: 'a' + } }, { - label: 'uses', + label: { + en: 'uses', + fr: 'usages' + }, to: '/uses', icon: 'i-ph-backpack-duotone', - shortcut: 'u' + shortcut: { + en: 'u', + fr: 'u' + } }, { - label: 'writings', + label: { + en: 'writings', + fr: 'écrits' + }, to: '/writings', icon: 'i-ph-books-duotone', - shortcut: 'w' + shortcut: { + en: 'w', + fr: 'e' + } }, { - label: 'resume', + label: { + en: 'resume', + fr: 'cv' + }, to: config.public.cloud.resume, target: '_blank', icon: 'i-ph-address-book-duotone', - shortcut: 'r' + shortcut: { + en: 'r', + fr: 'c' + } } ] async function toggleTheme() { - document.body.style.animation = 'theme-switch-on .5s' + document.body.style.animation = 'switch-on .5s' await new Promise(resolve => setTimeout(resolve, 500)) isDark.value = !isDark.value - document.body.style.animation = 'theme-switch-off .5s' + document.body.style.animation = 'switch-off .5s' await new Promise(resolve => setTimeout(resolve, 500)) document.body.style.animation = '' } +async function changeLocale() { + document.body.style.animation = 'switch-on .2s' + await new Promise(resolve => setTimeout(resolve, 200)) + + await setLocale(locale.value === 'en' ? 'fr' : 'en') + document.body.style.animation = 'switch-off .2s' + + await new Promise(resolve => setTimeout(resolve, 200)) + document.body.style.animation = '' +} + const router = useRouter() +const { locale, setLocale, locales, t } = useI18n() +const currentLocale = computed(() => locales.value.filter(l => l.code === locale.value)[0]) defineShortcuts({ h: () => router.push('/'), + a: () => router.push('/'), u: () => router.push('/uses'), w: () => router.push('/writings'), + e: () => router.push('/writings'), r: () => window.open(config.public.cloud.resume, '_blank'), - t: () => toggleTheme() + c: () => window.open(config.public.cloud.resume, '_blank'), + t: () => toggleTheme(), + l: () => changeLocale(), + backspace: () => router.back() }) + + +{ + "en": { + "offline": "I'm currently offline. Come back later to see what I'm working on.", + "working": "I'm actually working on {project}, editing {state}, using {editor}. I've started {start}, the {format}.", + "idling": "I'm idling on my computer with {editor} running in background.", + "tooltip": { + "online": "I'm online 👋", + "offline": "I'm offline 🫥", + "idling": "I'm sleeping 😴" + }, + "separator": "at" + }, + "fr": { + "offline": "Je suis actuellement hors ligne. Revenez plus tard pour voir sur quoi je travaille.", + "working": "Je travaille actuellement sur {project}, éditant {state}, en utilisant {editor}. J'ai commencé il y a {start}, le {format}.", + "idling": "Je suis en veille sur mon ordinateur avec {editor} en arrière-plan.", + "tooltip": { + "online": "Je suis connecté 👋", + "offline": "Je suis déconnecté 🫥", + "idling": "Je dors 😴" + }, + "separator": "à" + } +} + diff --git a/app/components/content/CatchPhrase.vue b/app/components/content/CatchPhrase.vue index badd992..30e7e56 100644 --- a/app/components/content/CatchPhrase.vue +++ b/app/components/content/CatchPhrase.vue @@ -8,11 +8,25 @@ class="transform -rotate-12 duration-300 group-hover:animate-wave" name="i-ph-hand-pointing-duotone" /> -

Hover the bold texts to find out more about me.

+

{{ t('quote') }}

+ + +{ + "en": { + "quote": "Hover the bold texts to find out more about me." + }, + "fr": { + "quote": "Survolez les textes en gras pour en savoir plus sur moi." + } +} + diff --git a/app/components/content/HoverText.vue b/app/components/content/HoverText.vue index 75ebcb3..c4b4bb1 100644 --- a/app/components/content/HoverText.vue +++ b/app/components/content/HoverText.vue @@ -17,10 +17,12 @@ defineProps({ diff --git a/app/components/content/ProseIcon.vue b/app/components/content/ProseIcon.vue index 3fd89f4..6b6a80c 100644 --- a/app/components/content/ProseIcon.vue +++ b/app/components/content/ProseIcon.vue @@ -8,7 +8,7 @@ defineProps({ + + + + +{ + "en": { + "quote": "Hello everyone! Thanks for visiting my portfolio. Please leave whatever you like to say, such as suggestions, appreciations, questions or anything!" + }, + "fr": { + "quote": "Bonjour tout le monde ! Merci de visiter mon portfolio. N'hésitez pas à laisser ce que vous avez à dire, comme des suggestions, des appréciations, des questions ou autre chose !" + } +} + diff --git a/app/components/content/Stats.vue b/app/components/content/Stats.vue index 74c68f6..4e30e6e 100644 --- a/app/components/content/Stats.vue +++ b/app/components/content/Stats.vue @@ -2,30 +2,65 @@ import type { Stats } from '~~/types' const { data: stats } = await useFetch('/api/stats') +const { t } = useI18n({ + useScope: 'local' +})