Is hutopy finally trilangual

This commit is contained in:
2025-04-19 01:56:59 -04:00
parent af71c5e952
commit b1681252cc
140 changed files with 5441 additions and 1085 deletions

View File

@@ -1,3 +0,0 @@
{
"alt": "Creator banner"
}

View File

@@ -1,3 +0,0 @@
{
"alt": "Banner del creador"
}

View File

@@ -1,3 +0,0 @@
{
"alt": "Bannière du créateur"
}

View File

@@ -1,5 +1,4 @@
<template>
<div class="relative">
<!-- Banner Container with mouse events -->
<div
@@ -35,7 +34,6 @@
></banner-editor>
</template>
</v-dialog>
</template>
<script setup>
@@ -43,11 +41,11 @@ import BannerEditor from "@/views/creators/BannerEditor.vue";
import {computed, ref} from "vue";
import {useBrandingStore} from "@/stores/brandingStore.js";
import {useAuthStore} from "@/stores/authStore.js";
import { useTranslations } from '@/translations/translations';
import { useI18n } from 'vue-i18n';
const authStore = useAuthStore();
const brandingStore = useBrandingStore();
const t = useTranslations();
const { t } = useI18n();
// State
const showTint = ref(false);
@@ -61,12 +59,24 @@ const openBannerEditor = () => {
const isCurrentCreator = computed(() => {
return authStore.userId === brandingStore.value.id;
});
</script>
<style scoped>
.banner {
@apply border-b border-solid border-hTertiary;
}
</style>
</style>
<i18n>
{
"en": {
"alt": "Creator banner"
},
"fr": {
"alt": "Bannière du créateur"
},
"es": {
"alt": "Banner del creador"
}
}
</i18n>

View File

@@ -1,12 +0,0 @@
{
"social": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Website"
}
}

View File

@@ -1,12 +0,0 @@
{
"social": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Sitio Web"
}
}

View File

@@ -1,12 +0,0 @@
{
"social": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Site Web"
}
}

View File

@@ -12,11 +12,11 @@ import Tiktok from "@/views/svg/Tiktok.vue";
import Reddit from "@/views/svg/Reddit.vue";
import Youtube from "@/views/svg/Youtube.vue";
import Web from "@/views/svg/Web.vue";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n'
const brandingStore = useBrandingStore();
const baseURL = window.location.origin;
const t = useTranslations();
const { t } = useI18n();
// Gèrer le breakpoint du block information.
// Définir un point de rupture pour "moyen" (correspondant à md: de Tailwind)
@@ -89,56 +89,56 @@ onUnmounted(() => {
<a v-if="brandingStore.value?.socials?.facebookUrl"
:href="brandingStore.value?.socials?.facebookUrl"
target="_blank"
:title="t('social.facebook')">
:title="t('facebook')">
<facebook class="social-icon"></facebook>
</a>
<a v-if="brandingStore.value?.socials?.instagramUrl"
:href="brandingStore.value?.socials?.instagramUrl"
target="_blank"
:title="t('social.instagram')">
:title="t('instagram')">
<instagram class="social-icon"></instagram>
</a>
<a v-if="brandingStore.value?.socials?.linkedInUrl"
:href="brandingStore.value?.socials?.linkedInUrl"
target="_blank"
:title="t('social.linkedin')">
:title="t('linkedin')">
<linkedin class="social-icon"></linkedin>
</a>
<a v-if="brandingStore.value?.socials?.redditUrl"
:href="brandingStore.value?.socials?.redditUrl"
target="_blank"
:title="t('social.reddit')">
:title="t('reddit')">
<reddit class="social-icon"></reddit>
</a>
<a v-if="brandingStore.value?.socials?.tikTokUrl"
:href="brandingStore.value?.socials?.tikTokUrl"
target="_blank"
:title="t('social.tiktok')">
:title="t('tiktok')">
<tiktok class="social-icon"></tiktok>
</a>
<a v-if="brandingStore.value?.socials?.xUrl"
:href="brandingStore.value?.socials?.xUrl"
target="_blank"
:title="t('social.x')">
:title="t('x')">
<x class="social-icon"></x>
</a>
<a v-if="brandingStore.value?.socials?.youtubeUrl"
:href="brandingStore.value?.socials?.youtubeUrl"
target="_blank"
:title="t('social.youtube')">
:title="t('youtube')">
<youtube class="social-icon"></youtube>
</a>
<a v-if="brandingStore.value?.socials?.websiteUrl"
:href="brandingStore.value?.socials?.websiteUrl"
target="_blank"
:title="t('social.website')">
:title="t('website')">
<web class="social-icon"></web>
</a>
@@ -166,4 +166,39 @@ onUnmounted(() => {
@apply flex flex-col gap-y-4;
}
}
</style>
</style>
<i18n>
{
"en": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Website"
},
"fr": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Site web"
},
"es": {
"facebook": "Facebook",
"instagram": "Instagram",
"linkedin": "LinkedIn",
"reddit": "Reddit",
"tiktok": "TikTok",
"x": "X (Twitter)",
"youtube": "YouTube",
"website": "Sitio web"
}
}
</i18n>

View File

@@ -1,7 +0,0 @@
{
"title": "Choose your Banner",
"description": "The banner must have a 3:1 ratio. Target dimensions are 960 x 320.",
"chooseImage": "Choose an image...",
"clickToEdit": "Click to edit",
"preview": "Banner preview"
}

View File

@@ -1,7 +0,0 @@
{
"title": "Elige tu Banner",
"description": "El banner debe tener una relación de 3:1. Las dimensiones objetivo son 960 x 320.",
"chooseImage": "Elegir una imagen...",
"clickToEdit": "Clic para editar",
"preview": "Vista previa del banner"
}

View File

@@ -1,7 +0,0 @@
{
"title": "Choisissez votre Bannière",
"description": "La bannière doit avoir un ratio de 3:1. Les dimensions cibles sont 960 x 320.",
"chooseImage": "Choisir une image...",
"clickToEdit": "Cliquez pour modifier",
"preview": "Aperçu de la bannière"
}

View File

@@ -72,7 +72,7 @@ import {ref} from 'vue'
import {useClient} from '@/plugins/api.js'
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n'
const props = defineProps({
creator: {
@@ -94,7 +94,7 @@ const TARGET_WIDTH = 960
const TARGET_HEIGHT = 320
// Get translations for this component
const t = useTranslations()
const { t } = useI18n()
const triggerFileInput = () => {
fileInput.value.click()
@@ -276,3 +276,20 @@ const cancel = () => {
@apply max-h-full;
}
</style>
<i18n>
{
"en": {
"chooseImage": "Choose an image",
"clickToEdit": "Click to edit"
},
"fr": {
"chooseImage": "Choisir une image",
"clickToEdit": "Cliquez pour modifier"
},
"es": {
"chooseImage": "Elegir una imagen",
"clickToEdit": "Haga clic para editar"
}
}
</i18n>

View File

@@ -1,3 +0,0 @@
{
"title": "Create your Hutopy"
}

View File

@@ -1,3 +0,0 @@
{
"title": "Crea tu Hutopy"
}

View File

@@ -1,3 +0,0 @@
{
"title": "Créez votre Hutopy"
}

View File

@@ -5,7 +5,7 @@ import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
import {useClient} from "@/plugins/api.js";
import {useRouter, useRoute} from "vue-router";
import NameEditor from "@/views/creators/NameEditor.vue";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n'
const creatorName = ref('');
const creatorNameReservationId = ref(undefined);
@@ -18,7 +18,7 @@ const router = useRouter();
const route = useRoute();
const creatorProfileStore = useCreatorProfileStore();
const userProfileStore = useUserProfileStore();
const t = useTranslations();
const { t } = useI18n();
function handleCreatorNameReservationIdChanged($event) {
creatorNameReservationId.value = $event
@@ -112,4 +112,33 @@ async function createAccount() {
@apply flex items-center justify-center;
}
</style>
</style>
<i18n>
{
"en": {
"title": "Create your Hutopy",
"cancel": "Cancel",
"create": "Create Creator Page",
"errors": {
"unexpected": "An unexpected error occurred"
}
},
"fr": {
"title": "Créez votre Hutopy",
"cancel": "Annuler",
"create": "Créer la page créateur",
"errors": {
"unexpected": "Une erreur inattendue s'est produite"
}
},
"es": {
"title": "Crea tu Hutopy",
"cancel": "Cancelar",
"create": "Crear página de creador",
"errors": {
"unexpected": "Se produjo un error inesperado"
}
}
}
</i18n>

View File

@@ -1,19 +0,0 @@
{
"sections": {
"about": {
"title": "About Us",
"description": "Description",
"mainImage": "Main image"
},
"support": {
"title": "Why Support Us",
"description": "Description",
"subtitle": "Subtitle"
}
},
"fields": {
"phoneNumber": "Phone Number",
"email": "Email Address",
"videoUrl": "Video URL"
}
}

View File

@@ -1,19 +0,0 @@
{
"sections": {
"about": {
"title": "Quiénes Somos",
"description": "Descripción",
"mainImage": "Imagen principal"
},
"support": {
"title": "Por Qué Apoyarnos",
"description": "Descripción",
"subtitle": "Subtítulo"
}
},
"fields": {
"phoneNumber": "Número de Teléfono",
"email": "Dirección de Correo",
"videoUrl": "URL del Video"
}
}

View File

@@ -1,19 +0,0 @@
{
"sections": {
"about": {
"title": "Qui sommes-nous",
"description": "Description",
"mainImage": "Image principale"
},
"support": {
"title": "Pourquoi nous supporter",
"description": "Description",
"subtitle": "Sous-titre"
}
},
"fields": {
"phoneNumber": "Numéro de Téléphone",
"email": "Adresse Email",
"videoUrl": "URL Vidéo"
}
}

View File

@@ -9,7 +9,7 @@
class="primary"
@click="isEditMode ? saveChanges() : toggleEditMode()"
>
{{ isEditMode ? t('save') : t('edit') }}
{{ isEditMode ? t('common.save') : t('common.edit') }}
</button>
<button
@@ -17,14 +17,14 @@
class="secondary"
@click="cancelEdit"
>
{{ t('cancel') }}
{{ t('common.cancel') }}
</button>
</div>
<!-- MainPage -->
<div class="flex flex-col mt-4">
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">{{ t('sections.about.title') }}</h1>
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">{{ t('creator.sections.about.title') }}</h1>
<div>
<!-- Main image Bloc D'information-->
@@ -35,7 +35,7 @@
{{ mainImageText }}
</p>
</div>
<v-textarea v-if="isEditMode" v-model="editableMainImageText" class="w-full p-2 py-6 " :label="t('sections.about.description')"
<v-textarea v-if="isEditMode" v-model="editableMainImageText" class="w-full p-2 py-6 " :label="t('creator.sections.about.description')"
variant="outlined"></v-textarea>
<div class="flex flex-row items-center space-x-4">
@@ -44,26 +44,26 @@
<img
v-if="mainImageUrl"
:src="mainImageUrl"
:alt="t('sections.about.mainImage')"
:alt="t('creator.sections.about.mainImage')"
class="max-w-full h-auto cursor-pointer"/>
</div>
<div v-if="isEditMode" class="relative flex justify-center">
<label>
<input class="hidden" type="file" @change="updateImage('mainImageUrl', $event)"/>
<img :src="mainImageUrl || fallbackImage"
:alt="t('sections.about.mainImage')"
:alt="t('creator.sections.about.mainImage')"
class=" max-w-full h-auto cursor-pointer max-h-96"/>
</label>
<button v-if="isEditMode"
class="absolute top-10 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
@click="deleteImage('mainImageUrl')">
{{ t('delete') }}
{{ t('common.delete') }}
</button>
</div>
<div class="w-1/2 flex flex-col justify-center">
<h2 v-if="videoSubtitleMain" class="text-xl font-semibold text-center">
{{ t('sections.support.title') }}
{{ t('creator.sections.support.title') }}
</h2>
<div v-if="!isEditMode">
@@ -76,7 +76,7 @@
<v-textarea
v-model="editableMainVideoText"
class="p-2 rounded-md mt-4"
:label="t('sections.support.description')"
:label="t('creator.sections.support.description')"
rows="10"
variant="outlined"
></v-textarea>
@@ -92,7 +92,7 @@
<v-text-field
v-model="editableVideoSubtitle"
class="w-full p-2"
:label="t('sections.support.subtitle')"
:label="t('creator.sections.support.subtitle')"
variant="outlined"
></v-text-field>
</div>
@@ -100,7 +100,7 @@
<v-textarea v-if="isEditMode"
v-model="editableVideoText"
class="w-full p-2"
:label="t('sections.support.description')"
:label="t('creator.sections.support.description')"
variant="outlined"
></v-textarea>
</div>
@@ -123,7 +123,7 @@
<v-text-field
v-model="editableVideoUrlMain"
class="w-full p-2 rounded-md"
:label="t('fields.videoUrl')"
:label="t('creator.fields.videoUrl')"
type="text"
variant="outlined"
/>
@@ -141,28 +141,28 @@
<!-- Première image -->
<div v-if="image1Url" class="relative w-full sm:flex-1 ">
<img :src="image1Url"
alt="Image 1"
:alt="t('creator.sections.about.image1')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</div>
<!-- Deuxième image -->
<div v-if="image2Url" class="relative w-full sm:flex-1 ">
<img :src="image2Url"
alt="Image 2"
:alt="t('creator.sections.about.image2')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</div>
<!-- Troisième image -->
<div v-if="image3Url" class="relative w-full sm:flex-1 ">
<img :src="image3Url"
alt="Image 3"
:alt="t('creator.sections.about.image3')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</div>
<!-- Quatrième image -->
<div v-if="image4Url" class="relative w-full sm:flex-1 ">
<img :src="image4Url"
alt="Image 4"
:alt="t('creator.sections.about.image4')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</div>
</div>
@@ -173,19 +173,19 @@
<div v-if="isEditMode" class="rounded-2xl">
<!--images-->
<div class=" text-2xl pa-2">Images</div>
<div class=" text-2xl pa-2">{{ t('creator.sections.about.images') }}</div>
<div class="pa-2 grid grid-cols-1 gap-4 md:grid-cols-4">
<!-- Première image -->
<div class="relative">
<label>
<input class="hidden" type="file" @change="updateImage('image1Url', $event)"/>
<img :src="image1Url || fallbackImage"
alt="Image 1"
:alt="t('creator.sections.about.image1')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</label>
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
@click="deleteImage('image1Url')">
X
{{ t('common.delete') }}
</button>
</div>
@@ -194,12 +194,12 @@
<label>
<input class="hidden" type="file" @change="updateImage('image2Url', $event)"/>
<img :src="image2Url || fallbackImage"
alt="Image 2"
:alt="t('creator.sections.about.image2')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</label>
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
@click="deleteImage('image2Url')">
X
{{ t('common.delete') }}
</button>
</div>
@@ -208,12 +208,12 @@
<label>
<input class="hidden" type="file" @change="updateImage('image3Url', $event)"/>
<img :src="image3Url || fallbackImage"
alt="Image 3"
:alt="t('creator.sections.about.image3')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</label>
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
@click="deleteImage('image3Url')">
X
{{ t('common.delete') }}
</button>
</div>
@@ -222,18 +222,18 @@
<label>
<input class="hidden" type="file" @change="updateImage('image4Url', $event)"/>
<img :src="image4Url || fallbackImage"
alt="Image 4"
:alt="t('creator.sections.about.image4')"
class="rounded-md max-w-full h-auto cursor-pointer"/>
</label>
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
@click="deleteImage('image4Url')">
X
{{ t('common.delete') }}
</button>
</div>
</div>
<!-- Description-->
<div class="text-2xl pa-2"> Description</div>
<div class="text-2xl pa-2">{{ t('creator.sections.about.description') }}</div>
</div>
<!--Edit-->
@@ -241,14 +241,14 @@
<v-text-field
v-model="editablePhoneNumber"
class="w-full p-2"
:label="t('fields.phoneNumber')"
:label="t('creator.fields.phoneNumber')"
variant="outlined"
></v-text-field>
<v-text-field
v-model="editableEmail"
class="w-full p-2"
:label="t('fields.email')"
:label="t('creator.fields.email')"
variant="outlined"
></v-text-field>
</div>
@@ -284,12 +284,12 @@ import {useClient} from "@/plugins/api.js";
import {useBrandingStore} from "@/stores/brandingStore.js";
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
import {useAuthStore} from "@/stores/authStore.js";
import {useTranslations} from '@/translations/translations'
import {useI18n} from 'vue-i18n';
const { t } = useI18n();
const authStore = useAuthStore();
const creatorProfileStore = useCreatorProfileStore();
const brandingStore = useBrandingStore();
const authStore = useAuthStore();
const t = useTranslations();
const client = useClient();
const isLoading = ref(true);
@@ -525,4 +525,105 @@ function cancelEdit() {
border: 0;
border-radius: 0.5rem; /* Pour les bords arrondis */
}
</style>
</style>
<i18n>
{
"en": {
"common": {
"save": "Save",
"edit": "Edit",
"cancel": "Cancel",
"delete": "Delete"
},
"creator": {
"sections": {
"about": {
"title": "About",
"description": "Description",
"mainImage": "Main image",
"image1": "Image 1",
"image2": "Image 2",
"image3": "Image 3",
"image4": "Image 4",
"images": "Images"
},
"support": {
"title": "Support",
"description": "Description",
"subtitle": "Subtitle"
}
},
"fields": {
"videoUrl": "Video URL",
"phoneNumber": "Phone Number",
"email": "Email"
}
}
},
"fr": {
"common": {
"save": "Enregistrer",
"edit": "Modifier",
"cancel": "Annuler",
"delete": "Supprimer"
},
"creator": {
"sections": {
"about": {
"title": "À propos",
"description": "Description",
"mainImage": "Image principale",
"image1": "Image 1",
"image2": "Image 2",
"image3": "Image 3",
"image4": "Image 4",
"images": "Images"
},
"support": {
"title": "Support",
"description": "Description",
"subtitle": "Sous-titre"
}
},
"fields": {
"videoUrl": "URL de la vidéo",
"phoneNumber": "Numéro de téléphone",
"email": "Email"
}
}
},
"es": {
"common": {
"save": "Guardar",
"edit": "Editar",
"cancel": "Cancelar",
"delete": "Eliminar"
},
"creator": {
"sections": {
"about": {
"title": "Acerca de",
"description": "Descripción",
"mainImage": "Imagen principal",
"image1": "Imagen 1",
"image2": "Imagen 2",
"image3": "Imagen 3",
"image4": "Imagen 4",
"images": "Imágenes"
},
"support": {
"title": "Soporte",
"description": "Descripción",
"subtitle": "Subtítulo"
}
},
"fields": {
"videoUrl": "URL del video",
"phoneNumber": "Número de teléfono",
"email": "Correo electrónico"
}
}
}
}
</i18n>

View File

@@ -1,5 +0,0 @@
{
"deletion": {
"pending": "This Creator page is pending deletion. You can revert the action in your profile."
}
}

View File

@@ -1,5 +0,0 @@
{
"deletion": {
"pending": "Esta página de creador está pendiente de eliminación. Puede revertir la acción en su perfil."
}
}

View File

@@ -1,5 +0,0 @@
{
"deletion": {
"pending": "Cette page de créateur est en attente de suppression. Vous pouvez annuler l'action dans votre profil."
}
}

View File

@@ -3,11 +3,11 @@ import {useBrandingStore} from "@/stores/brandingStore.js";
import {onMounted} from "vue";
import Banner from "@/views/creators/Banner.vue";
import Footer from "@/views/main/Footer.vue";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n';
const brandingStore = useBrandingStore();
const creatorName = window.location.pathname.split('/@').pop();
const t = useTranslations();
const { t } = useI18n();
onMounted(async () => {
await brandingStore.updateBrand(creatorName);
@@ -25,7 +25,7 @@ onMounted(async () => {
<div v-else>
<div v-if="brandingStore.value.isDeleted"
class="bg-red-500 p-2 m-4 text-center font-semibold">
{{ t('deletion.pending') }}
{{ t('creator.layout.deletion.pending') }}
</div>
<banner></banner>
<router-view></router-view>
@@ -35,3 +35,35 @@ onMounted(async () => {
</div>
</template>
<i18n>
{
"en": {
"creator": {
"layout": {
"deletion": {
"pending": "This creator page is pending deletion"
}
}
}
},
"fr": {
"creator": {
"layout": {
"deletion": {
"pending": "Cette page créateur est en attente de suppression"
}
}
}
},
"es": {
"creator": {
"layout": {
"deletion": {
"pending": "Esta página de creador está pendiente de eliminación"
}
}
}
}
}
</i18n>

View File

@@ -1,4 +0,0 @@
{
"alt": "Profile Picture",
"edit": "Edit Profile Picture"
}

View File

@@ -1,4 +0,0 @@
{
"alt": "Foto de perfil",
"edit": "Editar foto de perfil"
}

View File

@@ -1,4 +0,0 @@
{
"alt": "Photo de profil",
"edit": "Modifier la photo de profil"
}

View File

@@ -8,14 +8,14 @@
<img
class="shadow-2xl object-cover rounded-full border-solid border-hSecondary border-102 w-[200px] h-[200px] logo-image"
:src="brandingStore.value.images?.logo ?? '/images/placeholders/profile.png'"
:alt="t('alt')"
:alt="t('logoAlt')"
/>
<!-- Tint Effect -->
<div
v-if="showTint"
class="absolute rounded-full inset-0 bg-black/25 cursor-pointer"
:title="t('edit')"
:title="t('editLogo')"
>
<!-- Top-right Icon -->
<div
@@ -43,11 +43,11 @@ import {useAuthStore} from "@/stores/authStore.js";
import {useBrandingStore} from "@/stores/brandingStore.js";
import CreatorLogoEditor from "@/views/creators/CreatorLogoEditor.vue";
import {computed, ref} from "vue";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n'
const authStore = useAuthStore();
const brandingStore = useBrandingStore();
const t = useTranslations();
const { t } = useI18n();
// State
const showTint = ref(false);
@@ -69,4 +69,21 @@ const isCurrentCreator = computed(() => {
@apply border-b-4 border-t-4 border-solid border-hTertiary;
}
</style>
</style>
<i18n>
{
"en": {
"logoAlt": "Creator logo",
"editLogo": "Edit logo"
},
"fr": {
"logoAlt": "Logo du créateur",
"editLogo": "Modifier le logo"
},
"es": {
"logoAlt": "Logo del creador",
"editLogo": "Editar logo"
}
}
</i18n>

View File

@@ -1,7 +0,0 @@
{
"title": "Choose your Logo",
"description": "The logo must be square. Recommended dimensions are 200 x 200 pixels.",
"chooseImage": "Choose an image...",
"clickToEdit": "Click to edit",
"preview": "Logo preview"
}

View File

@@ -1,7 +0,0 @@
{
"title": "Elige tu Logo",
"description": "El logo debe ser cuadrado. Las dimensiones recomendadas son 200 x 200 píxeles.",
"chooseImage": "Elegir una imagen...",
"clickToEdit": "Clic para editar",
"preview": "Vista previa del logo"
}

View File

@@ -1,7 +0,0 @@
{
"title": "Choisissez votre Logo",
"description": "Le logo doit être carré. Les dimensions recommandées sont 200 x 200 pixels.",
"chooseImage": "Choisir une image...",
"clickToEdit": "Cliquez pour modifier",
"preview": "Aperçu du logo"
}

View File

@@ -1,12 +1,12 @@
<template>
<div class="card">
<div class="card-title">
{{ t('title') }}
{{ t('logoTitle') }}
</div>
<div class="card-content">
<p class="card-text">
{{ t('description') }}
{{ t('logoDescription') }}
</p>
<div class="file-input-container">
@@ -75,7 +75,7 @@ import {ref} from 'vue'
import {useClient} from '@/plugins/api.js'
import { Cropper, CircleStencil } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n';
const props = defineProps({
creator: {
@@ -96,8 +96,7 @@ const cropper = ref(null)
const TARGET_WIDTH = 200
const TARGET_HEIGHT = 200
// Get translations for this component
const t = useTranslations()
const { t } = useI18n();
const triggerFileInput = () => {
fileInput.value.click()
@@ -292,3 +291,26 @@ const cancel = () => {
}
</style>
<i18n>
{
"en": {
"logoTitle": "Edit Logo",
"logoDescription": "Choose a logo image for your creator page. The image will be cropped to a circle.",
"chooseImage": "Choose Image",
"clickToEdit": "Click to edit"
},
"fr": {
"logoTitle": "Modifier le logo",
"logoDescription": "Choisissez une image de logo pour votre page de créateur. L'image sera recadrée en cercle.",
"chooseImage": "Choisir une image",
"clickToEdit": "Cliquez pour modifier"
},
"es": {
"logoTitle": "Editar logo",
"logoDescription": "Elige una imagen de logo para tu página de creador. La imagen se recortará en círculo.",
"chooseImage": "Elegir imagen",
"clickToEdit": "Haz clic para editar"
}
}
</i18n>

View File

@@ -1,10 +0,0 @@
{
"isupport": "I Support",
"amount": "Amount",
"message": "Message",
"send": "Send",
"cancel": "Cancel",
"errors": {
"payment": "An error occurred during payment processing"
}
}

View File

@@ -1,10 +0,0 @@
{
"isupport": "Apoyo",
"amount": "Cantidad",
"message": "Mensaje",
"send": "Enviar",
"cancel": "Cancelar",
"errors": {
"payment": "Ocurrió un error durante el procesamiento del pago"
}
}

View File

@@ -1,10 +0,0 @@
{
"isupport": "Je Soutiens",
"amount": "Montant",
"message": "Message",
"send": "Envoyer",
"cancel": "Annuler",
"errors": {
"payment": "Une erreur s'est produite lors du traitement du paiement"
}
}

View File

@@ -3,13 +3,13 @@
class="secondary donation-action"
@click="openDonationDialog()"
>
{{ t('isupport') }}
{{ t('creator.donation.isupport') }}
</button>
<v-dialog v-model="donationModal">
<div class="card">
<div class="card-title">
{{ t('isupport') }}
{{ t('creator.donation.isupport') }}
</div>
<div class="card-content">
@@ -20,7 +20,7 @@
placeholder="0"
:min="0"
class="p-2"
:label="t('amount')"
:label="t('creator.donation.amount')"
density="comfortable"
variant="outlined"
hide-details
@@ -32,7 +32,7 @@
<v-textarea
v-model="tipMessage"
:label="t('message')"
:label="t('creator.donation.message')"
class="p-2"
density="comfortable"
variant="outlined"
@@ -45,12 +45,12 @@
<button class="secondary"
@click="closeDonationDialog()">
{{ t('cancel') }}
{{ t('common.cancel') }}
</button>
<button class="primary"
@click="goPay()">
{{ t('send') }}
{{ t('creator.donation.send') }}
</button>
</div>
@@ -71,7 +71,7 @@
class="ma-auto"
style="width: 200px"
@click="closeDialog()"
>{{ t('cancel') }}
>{{ t('common.cancel') }}
</v-btn>
</v-card-actions>
</v-card>
@@ -84,10 +84,10 @@ import {useClient} from '@/plugins/api.js';
import {useBrandingStore} from '@/stores/brandingStore.js';
import {loadStripe} from '@stripe/stripe-js';
import {onMounted, ref} from 'vue';
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n';
const brandingStore = useBrandingStore();
const t = useTranslations();
const { t } = useI18n();
const props = defineProps({
creatorId: {default: 'missing-creator-id', required: true},
@@ -136,7 +136,7 @@ async function createCheckoutSession() {
return clientSecret.data;
} catch (error) {
console.error(error);
errorMessage.value = t('errors.payment');
errorMessage.value = t('creator.donation.errors.payment');
}
}
@@ -185,3 +185,56 @@ function preventNonNumeric(event) {
padding: 5px;
}
</style>
<i18n>
{
"en": {
"common": {
"cancel": "Cancel"
},
"creator": {
"donation": {
"isupport": "I Support",
"amount": "Amount ($)",
"message": "Message (optional)",
"send": "Send",
"errors": {
"payment": "An error occurred during payment processing"
}
}
}
},
"fr": {
"common": {
"cancel": "Annuler"
},
"creator": {
"donation": {
"isupport": "Je Soutiens",
"amount": "Montant ($)",
"message": "Message (optionnel)",
"send": "Envoyer",
"errors": {
"payment": "Une erreur s'est produite lors du traitement du paiement"
}
}
}
},
"es": {
"common": {
"cancel": "Cancelar"
},
"creator": {
"donation": {
"isupport": "Apoyo",
"amount": "Cantidad ($)",
"message": "Mensaje (opcional)",
"send": "Enviar",
"errors": {
"payment": "Ocurrió un error durante el procesamiento del pago"
}
}
}
}
}
</i18n>

View File

@@ -1,3 +0,0 @@
{
"label": "Page name"
}

View File

@@ -1,3 +0,0 @@
{
"label": "Nombre de la página"
}

View File

@@ -1,4 +0,0 @@
{
"label": "Nom de la page"
}
}

View File

@@ -2,7 +2,7 @@
import {ref, onMounted, onUnmounted} from "vue";
import {v7} from "uuid";
import {useClient} from "@/plugins/api.js";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n';
const props = defineProps({
name: {
@@ -19,7 +19,7 @@ const emits = defineEmits([
]);
const name = ref(props.name);
const t = useTranslations();
const { t } = useI18n();
const isOperationPending = ref(false);
const reservationState = ref(null);
@@ -112,7 +112,7 @@ onUnmounted(() => {
<template>
<v-text-field
variant="outlined"
:label="t('label')"
:label="t('creator.name.label')"
v-model="name"
outlined
@input="handleInput"
@@ -134,4 +134,30 @@ onUnmounted(() => {
<style scoped>
</style>
</style>
<i18n>
{
"en": {
"creator": {
"name": {
"label": "Page name"
}
}
},
"fr": {
"creator": {
"name": {
"label": "Nom de la page"
}
}
},
"es": {
"creator": {
"name": {
"label": "Nombre de la página"
}
}
}
}
</i18n>

View File

@@ -1,3 +0,0 @@
{
"verified": "Verified Account"
}

View File

@@ -1,3 +0,0 @@
{
"verified": "Cuenta Verificada"
}

View File

@@ -1,3 +0,0 @@
{
"verified": "Compte Vérifié"
}

View File

@@ -21,8 +21,22 @@
<script setup>
import IconAccountVerified from "@/components/icons/IconAccountVerified.vue";
import {useBrandingStore} from "@/stores/brandingStore.js";
import { useTranslations } from '@/translations/translations'
import { useI18n } from 'vue-i18n';
const brandingStore = useBrandingStore();
const t = useTranslations();
</script>
const { t } = useI18n();
</script>
<i18n>
{
"en": {
"verified": "Verified Account"
},
"fr": {
"verified": "Compte vérifié"
},
"es": {
"verified": "Cuenta verificada"
}
}
</i18n>