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 } from '@/i18n'
|
||||
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import ReleaseNotes from '@/components/ReleaseNotes.vue'
|
||||
import ServerCommand from '@/components/ServerCommand.vue'
|
||||
@@ -61,8 +63,12 @@ const READY_HINT =
|
||||
const LIMITED_BLOCK: Block = {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-info',
|
||||
title: 'Too many tries',
|
||||
text: 'Wait a moment before trying again.',
|
||||
get title() {
|
||||
return t('Too many tries')
|
||||
},
|
||||
get text() {
|
||||
return t('Wait a moment before trying again.')
|
||||
},
|
||||
}
|
||||
const ZERO_PROGRESS = { percent: 0, downloaded_bytes: 0, total_bytes: 0 }
|
||||
|
||||
@@ -147,47 +153,90 @@ const applyBlocks = computed<Record<ApplyView, Block>>(() => ({
|
||||
available: {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-circle-arrow-up',
|
||||
title: `Version ${newVersion.value} is available`,
|
||||
text: `You have ${props.status.current}. Update downloads the new version and checks it. Nothing changes until you restart.`,
|
||||
get title() {
|
||||
return t('Version {0} is available', [newVersion.value])
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'You have {0}. Update downloads the new version and checks it. Nothing changes until you restart.',
|
||||
[props.status.current],
|
||||
)
|
||||
},
|
||||
meta: lastChecked.value,
|
||||
},
|
||||
downloading: {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-download',
|
||||
title: `Downloading version ${newVersion.value}…`,
|
||||
text: 'You can leave this page. The download continues and your site stays online.',
|
||||
get title() {
|
||||
return t('Downloading version {0}…', [newVersion.value])
|
||||
},
|
||||
get text() {
|
||||
return t('You can leave this page. The download continues and your site stays online.')
|
||||
},
|
||||
},
|
||||
verifying: {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-shield-check',
|
||||
title: 'Checking the download…',
|
||||
text: 'Making sure the file is complete and safe to install. This takes a few seconds.',
|
||||
get title() {
|
||||
return t('Checking the download…')
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'Making sure the file is complete and safe to install. This takes a few seconds.',
|
||||
)
|
||||
},
|
||||
},
|
||||
ready: {
|
||||
tone: 'success',
|
||||
icon: 'i-lucide-circle-check',
|
||||
title: `Version ${newVersion.value} is ready to install`,
|
||||
text: 'The download is checked. Restart to install it. Your site will be unavailable for about 10 seconds.',
|
||||
meta: 'Nothing has changed yet.',
|
||||
get title() {
|
||||
return t('Version {0} is ready to install', [newVersion.value])
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'The download is checked. Restart to install it. Your site will be unavailable for about 10 seconds.',
|
||||
)
|
||||
},
|
||||
meta: t('Nothing has changed yet.'),
|
||||
},
|
||||
'download-failed': {
|
||||
tone: 'error',
|
||||
icon: 'i-lucide-circle-x',
|
||||
title: "The download didn't finish",
|
||||
text: 'The connection dropped before the file was complete. Nothing was changed and your site is running as before.',
|
||||
get title() {
|
||||
return t("The download didn't finish")
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'The connection dropped before the file was complete. Nothing was changed and your site is running as before.',
|
||||
)
|
||||
},
|
||||
},
|
||||
'verification-failed': {
|
||||
tone: 'warning',
|
||||
icon: 'i-lucide-triangle-alert',
|
||||
title: "We didn't use this update",
|
||||
text: "The file didn't pass our safety check, so it was not installed. Nothing was changed. Try downloading it again. If this keeps happening, contact RenewCMS support.",
|
||||
get title() {
|
||||
return t("We didn't use this update")
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
"The file didn't pass our safety check, so it was not installed. Nothing was changed. Try downloading it again. If this keeps happening, contact RenewCMS support.",
|
||||
)
|
||||
},
|
||||
},
|
||||
'rolled-back': {
|
||||
tone: 'warning',
|
||||
icon: 'i-lucide-triangle-alert',
|
||||
title: "The update didn't install",
|
||||
text: 'RenewCMS put the previous version back, so your site is running as before. Nothing was lost.',
|
||||
meta: 'What to do next: try again in a few minutes. If it fails again, ask whoever manages your server to check the update.',
|
||||
get title() {
|
||||
return t("The update didn't install")
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'RenewCMS put the previous version back, so your site is running as before. Nothing was lost.',
|
||||
)
|
||||
},
|
||||
meta: t(
|
||||
'What to do next: try again in a few minutes. If it fails again, ask whoever manages your server to check the update.',
|
||||
),
|
||||
},
|
||||
limited: LIMITED_BLOCK,
|
||||
}))
|
||||
@@ -196,13 +245,23 @@ const progressView = computed<ProgressView | null>(() => {
|
||||
if (applyView.value === 'downloading') {
|
||||
const progress = props.status.progress ?? ZERO_PROGRESS
|
||||
return {
|
||||
label: `Downloading version ${newVersion.value}`,
|
||||
get label() {
|
||||
return t('Downloading version {0}', [newVersion.value])
|
||||
},
|
||||
text: props.status.progress ? formatDownloadProgress(progress) : '0%',
|
||||
value: progress.percent,
|
||||
}
|
||||
}
|
||||
if (applyView.value === 'verifying') {
|
||||
return { label: VERIFYING_ANNOUNCEMENT, text: 'Almost there', value: null }
|
||||
return {
|
||||
get label() {
|
||||
return t(VERIFYING_ANNOUNCEMENT)
|
||||
},
|
||||
get text() {
|
||||
return t('Almost there')
|
||||
},
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
@@ -211,23 +270,25 @@ const announcement = computed(() => {
|
||||
if (applyView.value === 'downloading') {
|
||||
return downloadAnnouncement(newVersion.value, props.status.progress?.percent ?? 0)
|
||||
}
|
||||
return applyView.value === 'verifying' ? VERIFYING_ANNOUNCEMENT : ''
|
||||
return applyView.value === 'verifying' ? t(VERIFYING_ANNOUNCEMENT) : ''
|
||||
})
|
||||
|
||||
const hint = computed(() => {
|
||||
if (applyView.value === 'available') {
|
||||
return AVAILABLE_HINT
|
||||
return t(AVAILABLE_HINT)
|
||||
}
|
||||
if (applyView.value === 'ready') {
|
||||
return READY_HINT
|
||||
return t(READY_HINT)
|
||||
}
|
||||
return showRestartHint.value ? RESTART_HINT : null
|
||||
return showRestartHint.value ? t(RESTART_HINT) : null
|
||||
})
|
||||
|
||||
function applyButton(view: ApplyView): ActionButton {
|
||||
if (isStarting.value || view === 'downloading' || view === 'verifying') {
|
||||
return {
|
||||
label: 'Updating…',
|
||||
get label() {
|
||||
return t('Updating…')
|
||||
},
|
||||
icon: 'i-lucide-loader-circle',
|
||||
primary: false,
|
||||
disabled: true,
|
||||
@@ -236,7 +297,9 @@ function applyButton(view: ApplyView): ActionButton {
|
||||
}
|
||||
if (view === 'ready') {
|
||||
return {
|
||||
label: 'Restart',
|
||||
get label() {
|
||||
return t('Restart')
|
||||
},
|
||||
icon: 'i-lucide-power',
|
||||
primary: true,
|
||||
disabled: false,
|
||||
@@ -249,7 +312,9 @@ function applyButton(view: ApplyView): ActionButton {
|
||||
}
|
||||
if (view === 'available') {
|
||||
return {
|
||||
label: 'Update',
|
||||
get label() {
|
||||
return t('Update')
|
||||
},
|
||||
icon: 'i-lucide-download',
|
||||
primary: true,
|
||||
disabled: false,
|
||||
@@ -257,7 +322,9 @@ function applyButton(view: ApplyView): ActionButton {
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: 'Try again',
|
||||
get label() {
|
||||
return t('Try again')
|
||||
},
|
||||
icon: 'i-lucide-rotate-cw',
|
||||
primary: true,
|
||||
disabled: false,
|
||||
@@ -270,8 +337,12 @@ const block = computed<Block>(() => {
|
||||
return {
|
||||
tone: 'neutral',
|
||||
icon: 'i-lucide-loader-circle',
|
||||
title: 'Checking for updates…',
|
||||
text: 'This usually takes a few seconds.',
|
||||
get title() {
|
||||
return t('Checking for updates…')
|
||||
},
|
||||
get text() {
|
||||
return t('This usually takes a few seconds.')
|
||||
},
|
||||
}
|
||||
}
|
||||
if (isOwner.value && props.phase === 'limited') {
|
||||
@@ -281,8 +352,14 @@ const block = computed<Block>(() => {
|
||||
return {
|
||||
tone: 'warning',
|
||||
icon: 'i-lucide-wifi-off',
|
||||
title: "Couldn't check for updates",
|
||||
text: "RenewCMS couldn't reach the update server. Check your connection and try again. Your site isn't affected.",
|
||||
get title() {
|
||||
return t("Couldn't check for updates")
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
"RenewCMS couldn't reach the update server. Check your connection and try again. Your site isn't affected.",
|
||||
)
|
||||
},
|
||||
meta: lastChecked.value,
|
||||
}
|
||||
}
|
||||
@@ -293,8 +370,12 @@ const block = computed<Block>(() => {
|
||||
return {
|
||||
tone: 'success',
|
||||
icon: 'i-lucide-circle-check',
|
||||
title: `You're on version ${displayVersion(props.status.current)}`,
|
||||
text: 'The update is installed and your site is running again.',
|
||||
get title() {
|
||||
return t("You're on version {0}", [displayVersion(props.status.current)])
|
||||
},
|
||||
get text() {
|
||||
return t('The update is installed and your site is running again.')
|
||||
},
|
||||
meta: props.status.finished_at ? formatUpdatedAt(props.status.finished_at) : undefined,
|
||||
}
|
||||
}
|
||||
@@ -302,25 +383,42 @@ const block = computed<Block>(() => {
|
||||
return {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-info',
|
||||
title: `Version ${newVersion.value} is available`,
|
||||
text: "This site can't update itself from the browser yet. Whoever manages your server can set it up once, or update RenewCMS for you.",
|
||||
get title() {
|
||||
return t('Version {0} is available', [newVersion.value])
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
"This site can't update itself from the browser yet. Whoever manages your server can set it up once, or update RenewCMS for you.",
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
if (props.status.available) {
|
||||
return {
|
||||
tone: 'info',
|
||||
icon: 'i-lucide-circle-arrow-up',
|
||||
title: `Version ${newVersion.value} is available`,
|
||||
text: `You have ${props.status.current}. Only the owner can update RenewCMS. Ask the owner of this site.`,
|
||||
get title() {
|
||||
return t('Version {0} is available', [newVersion.value])
|
||||
},
|
||||
get text() {
|
||||
return t(
|
||||
'You have {0}. Only the owner can update RenewCMS. Ask the owner of this site.',
|
||||
[props.status.current],
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
tone: 'success',
|
||||
icon: 'i-lucide-circle-check',
|
||||
title: "You're up to date",
|
||||
text: isOwner.value
|
||||
? 'You have the latest version of RenewCMS.'
|
||||
: 'Only the owner can update or restart the site.',
|
||||
get title() {
|
||||
return t("You're up to date")
|
||||
},
|
||||
get text() {
|
||||
return isOwner.value
|
||||
? t('You have the latest version of RenewCMS.')
|
||||
: t('Only the owner can update or restart the site.')
|
||||
},
|
||||
meta: isOwner.value ? lastChecked.value : undefined,
|
||||
}
|
||||
})
|
||||
@@ -342,7 +440,9 @@ const showServerGuidance = computed(
|
||||
)
|
||||
|
||||
const plainRestartButton: ActionButton = {
|
||||
label: 'Restart',
|
||||
get label() {
|
||||
return t('Restart')
|
||||
},
|
||||
icon: 'i-lucide-power',
|
||||
primary: false,
|
||||
disabled: false,
|
||||
@@ -357,7 +457,9 @@ const actionButtons = computed<ActionButton[]>(() => {
|
||||
if (props.phase === 'checking') {
|
||||
return [
|
||||
{
|
||||
label: 'Checking…',
|
||||
get label() {
|
||||
return t('Checking…')
|
||||
},
|
||||
icon: 'i-lucide-loader-circle',
|
||||
primary: false,
|
||||
disabled: true,
|
||||
@@ -367,7 +469,9 @@ const actionButtons = computed<ActionButton[]>(() => {
|
||||
}
|
||||
if (props.phase === 'failed') {
|
||||
return withPlainRestart({
|
||||
label: 'Try again',
|
||||
get label() {
|
||||
return t('Try again')
|
||||
},
|
||||
icon: 'i-lucide-rotate-cw',
|
||||
primary: true,
|
||||
disabled: false,
|
||||
@@ -384,7 +488,9 @@ const actionButtons = computed<ActionButton[]>(() => {
|
||||
return []
|
||||
}
|
||||
return withPlainRestart({
|
||||
label: 'Check for updates',
|
||||
get label() {
|
||||
return t('Check for updates')
|
||||
},
|
||||
icon: 'i-lucide-refresh-cw',
|
||||
primary: false,
|
||||
disabled: false,
|
||||
@@ -401,14 +507,18 @@ function withPlainRestart(button: ActionButton) {
|
||||
function limitedButton(action: ButtonAction): ActionButton {
|
||||
return props.retryActive
|
||||
? {
|
||||
label: `Try again in ${props.retryLabel}`,
|
||||
get label() {
|
||||
return t('Try again in {0}', [props.retryLabel])
|
||||
},
|
||||
icon: 'i-lucide-clock',
|
||||
primary: false,
|
||||
disabled: true,
|
||||
action: null,
|
||||
}
|
||||
: {
|
||||
label: 'Try again',
|
||||
get label() {
|
||||
return t('Try again')
|
||||
},
|
||||
icon: 'i-lucide-rotate-cw',
|
||||
primary: false,
|
||||
disabled: false,
|
||||
@@ -458,7 +568,7 @@ const notes = computed(() => {
|
||||
tabindex="-1"
|
||||
class="self-start text-lg font-semibold text-highlighted focus:outline-2 focus:outline-offset-4 focus:outline-primary"
|
||||
>
|
||||
Updates
|
||||
{{ t('Updates') }}
|
||||
</h2>
|
||||
|
||||
<UpdateStatusBlock
|
||||
@@ -516,7 +626,7 @@ const notes = computed(() => {
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1.5 self-start text-sm font-medium text-highlighted underline underline-offset-3"
|
||||
>
|
||||
How to update
|
||||
{{ t('How to update') }}
|
||||
<UIcon name="i-lucide-arrow-up-right" class="size-3.5" />
|
||||
</a>
|
||||
|
||||
@@ -527,7 +637,7 @@ const notes = computed(() => {
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1.5 self-start text-sm font-medium text-highlighted underline underline-offset-3"
|
||||
>
|
||||
Read the release notes
|
||||
{{ t('Read the release notes') }}
|
||||
<UIcon name="i-lucide-arrow-up-right" class="size-3.5" />
|
||||
</a>
|
||||
</section>
|
||||
|
||||
Reference in new issue
Block a user