feat(SPA): i18n internationzalization, english and french
This commit is contained in:
1 parent
7f1e8e572d
commit
721311a643
88 files changed
+4438
-1148
No files matched your search
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { t, translate } from '@/i18n'
|
||||
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import CharacterCounter from '@/components/CharacterCounter.vue'
|
||||
import { ApiError, useApi } from '@/composables/useApi'
|
||||
@@ -34,10 +36,10 @@ const titleLengthError = computed(() => {
|
||||
return ''
|
||||
}
|
||||
if (titleLength.value < TITLE_MIN_LENGTH) {
|
||||
return 'Use at least 3 characters.'
|
||||
return t('Use at least 3 characters.')
|
||||
}
|
||||
if (titleLength.value > TITLE_MAX_LENGTH) {
|
||||
return 'Use 3 to 200 characters.'
|
||||
return t('Use 3 to 200 characters.')
|
||||
}
|
||||
return ''
|
||||
})
|
||||
@@ -46,7 +48,7 @@ const titleError = computed(() => titleServerError.value || titleLengthError.val
|
||||
|
||||
const bodyError = computed(() =>
|
||||
bodyTouched.value && !bodyValid.value
|
||||
? 'Add a first paragraph. It can be a single sentence.'
|
||||
? t('Add a first paragraph. It can be a single sentence.')
|
||||
: '',
|
||||
)
|
||||
|
||||
@@ -56,10 +58,10 @@ const showHelp = computed(() => !submitting.value && formAlert.value === '')
|
||||
|
||||
const alertMessage = computed(() => {
|
||||
if (formAlert.value === 'invalid') {
|
||||
return "Something in the form isn't valid. Check the highlighted fields."
|
||||
return t("Something in the form isn't valid. Check the highlighted fields.")
|
||||
}
|
||||
if (formAlert.value === 'failed') {
|
||||
return "Couldn't create the article. Your text is still here. Try again in a moment."
|
||||
return t("Couldn't create the article. Your text is still here. Try again in a moment.")
|
||||
}
|
||||
return ''
|
||||
})
|
||||
@@ -78,7 +80,9 @@ function resetForm() {
|
||||
async function focusTitleField() {
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
document.querySelector<HTMLInputElement>(`input[placeholder="${TITLE_PLACEHOLDER}"]`)?.focus()
|
||||
document
|
||||
.querySelector<HTMLInputElement>(`input[placeholder="${t(TITLE_PLACEHOLDER)}"]`)
|
||||
?.focus()
|
||||
titleFocused.value = true
|
||||
}
|
||||
|
||||
@@ -147,8 +151,8 @@ function onCancel() {
|
||||
<template>
|
||||
<UModal
|
||||
v-model:open="open"
|
||||
title="New article"
|
||||
description="It's saved as a draft. Titles can't be changed later, so check it now."
|
||||
:title="t('New article')"
|
||||
:description="t('It\'s saved as a draft. Titles can\'t be changed later, so check it now.')"
|
||||
:dismissible="!submitting"
|
||||
:ui="{
|
||||
content:
|
||||
@@ -173,7 +177,11 @@ function onCancel() {
|
||||
:description="alertMessage"
|
||||
/>
|
||||
<UForm :state="{ title, body }" class="flex flex-col gap-4">
|
||||
<UFormField label="Title" name="title" :error="titleError || undefined">
|
||||
<UFormField
|
||||
:label="t('Title')"
|
||||
name="title"
|
||||
:error="translate(titleError) || undefined"
|
||||
>
|
||||
<template #hint>
|
||||
<CharacterCounter
|
||||
:value="titleLength"
|
||||
@@ -188,13 +196,15 @@ function onCancel() {
|
||||
name="i-lucide-circle-alert"
|
||||
class="size-3.5 shrink-0 text-error"
|
||||
/>
|
||||
{{ error }}
|
||||
{{ t(error) }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="showHelp" #help>3 to 200 characters.</template>
|
||||
<template v-else-if="showHelp" #help>{{
|
||||
t('3 to 200 characters.')
|
||||
}}</template>
|
||||
<UInput
|
||||
v-model="title"
|
||||
:placeholder="TITLE_PLACEHOLDER"
|
||||
:placeholder="t(TITLE_PLACEHOLDER)"
|
||||
:disabled="submitting"
|
||||
color="primary"
|
||||
:highlight="titleFocused || !!titleError"
|
||||
@@ -204,22 +214,26 @@ function onCancel() {
|
||||
@blur="onTitleBlur"
|
||||
/>
|
||||
</UFormField>
|
||||
<UFormField label="First paragraph" name="body" :error="bodyError || undefined">
|
||||
<UFormField
|
||||
:label="t('First paragraph')"
|
||||
name="body"
|
||||
:error="bodyError || undefined"
|
||||
>
|
||||
<template v-if="bodyError" #error="{ error }">
|
||||
<span class="flex items-center gap-1.5">
|
||||
<UIcon
|
||||
name="i-lucide-circle-alert"
|
||||
class="size-3.5 shrink-0 text-error"
|
||||
/>
|
||||
{{ error }}
|
||||
{{ t(error) }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="showHelp" #help>
|
||||
You can format it and add images in the editor.
|
||||
{{ t('You can format it and add images in the editor.') }}
|
||||
</template>
|
||||
<UTextarea
|
||||
v-model="body"
|
||||
placeholder="Start writing. You'll continue in the editor."
|
||||
:placeholder="t('Start writing. You\'ll continue in the editor.')"
|
||||
:disabled="submitting"
|
||||
:highlight="!!bodyError"
|
||||
:rows="3"
|
||||
@@ -244,7 +258,7 @@ function onCancel() {
|
||||
:disabled="submitting"
|
||||
@click="onCancel"
|
||||
>
|
||||
Cancel
|
||||
{{ t('Cancel') }}
|
||||
</UButton>
|
||||
<UButton
|
||||
block
|
||||
@@ -254,7 +268,7 @@ function onCancel() {
|
||||
:disabled="submitting"
|
||||
@click="onSubmit"
|
||||
>
|
||||
{{ submitting ? 'Creating…' : 'Create draft' }}
|
||||
{{ submitting ? t('Creating…') : t('Create draft') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in new issue
Block a user