i18n Support and Task improvements (#80)

* fix: release workflow

* feat: move mostly to internal tasks system

* feat: migrate object clean to new task system

* fix: release not  getting good base version

* chore: set version v0.3.0

* chore: style

* feat: basic task concurrency

* feat: temp pages to fill in page links

* feat: inital i18n support

* feat: localize store page

* chore: style

* fix: weblate doesn't like multifile thing

* fix: update nuxt

* feat: improved error logging

* fix: using old task api

* feat: basic translation docs

* feat: add i18n eslint plugin

* feat: translate store and auth pages

* feat: more translation progress

* feat: admin dash i18n progress

* feat: enable update check by default in prod

* fix: using wrong i18n keys

* fix: crash in library sources page

* feat: finish i18n work

* fix: missing i18n translations

* feat: use twemoji for emojis

* feat: sanatize object ids

* fix: EmojiText's alt text

* fix: UserWidget not using links

* feat: cache and auth for emoji api

* fix: add more missing translations
This commit is contained in:
Husky
2025-06-04 19:53:30 -04:00
committed by GitHub
parent c7fab132ab
commit 681efe95af
86 changed files with 5175 additions and 2816 deletions
+40 -29
View File
@@ -2,10 +2,11 @@
<div>
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<h1 class="text-base font-semibold text-zinc-100">Library Sources</h1>
<h1 class="text-base font-semibold text-zinc-100">
{{ $t("library.admin.sources.sources") }}
</h1>
<p class="mt-2 text-sm text-zinc-400">
Configure your library sources, where Drop will look for new games and
versions to import.
{{ $t("library.admin.sources.desc") }}
</p>
</div>
<div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
@@ -13,7 +14,7 @@
class="block rounded-md bg-blue-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
@click="() => (actionSourceOpen = true)"
>
Create
{{ $t("create") }}
</button>
</div>
</div>
@@ -27,28 +28,28 @@
scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-zinc-100 sm:pl-3"
>
Name
{{ $t("name") }}
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
>
Type
{{ $t("type") }}
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
>
Working?
{{ $t("library.admin.sources.working") }}
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
>
Options
{{ $t("options") }}
</th>
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-3">
<span class="sr-only">Edit</span>
<span class="sr-only">{{ $t("edit") }}</span>
</th>
</tr>
</thead>
@@ -83,14 +84,20 @@
class="text-blue-500 hover:text-blue-400"
@click="() => edit(sourceIdx)"
>
Edit<span class="sr-only">, {{ source.name }}</span>
{{ $t("edit") }}
<span class="sr-only">
{{ $t("chars.srComma", [source.name]) }}
</span>
</button>
<button
class="text-red-500 hover:text-red-400"
@click="() => deleteSource(sourceIdx)"
>
Delete<span class="sr-only">, {{ source.name }}</span>
{{ $t("delete") }}
<span class="sr-only">
{{ $t("chars.srComma", [source.name]) }}
</span>
</button>
</td>
</tr>
@@ -104,11 +111,10 @@
<template #default>
<div>
<DialogTitle as="h3" class="text-lg font-medium leading-6 text-white">
Create source
{{ $t("library.admin.sources.create") }}
</DialogTitle>
<p class="mt-1 text-zinc-400 text-sm">
Drop will use this source to access your game library, and make them
available.
{{ $t("library.admin.sources.createDesc") }}
</p>
</div>
<form
@@ -119,10 +125,10 @@
<label
for="name"
class="block text-sm font-medium leading-6 text-zinc-100"
>Name</label
>{{ $t("name") }}</label
>
<p class="text-zinc-400 block text-xs font-medium leading-6">
The name of your source, for reference.
{{ $t("library.admin.sources.nameDesc") }}
</p>
<div class="mt-2">
<input
@@ -131,21 +137,23 @@
name="name"
type="text"
autocomplete="name"
placeholder="My New Source"
:placeholder="$t('library.admin.sources.namePlaceholder')"
class="block w-full rounded-md border-0 py-1.5 px-3 bg-zinc-800 disabled:bg-zinc-900/80 text-zinc-100 disabled:text-zinc-400 shadow-sm ring-1 ring-inset ring-zinc-700 disabled:ring-zinc-800 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div v-if="createMode">
<label class="block text-sm font-medium leading-6 text-zinc-100"
>Type</label
>
<label class="block text-sm font-medium leading-6 text-zinc-100">{{
$t("type")
}}</label>
<p class="text-zinc-400 block text-xs font-medium leading-6">
The type of your source. Changes the required options.
{{ $t("library.admin.sources.typeDesc") }}
</p>
<RadioGroup v-model="currentSourceOption" class="mt-2">
<RadioGroupLabel class="sr-only">Type</RadioGroupLabel>
<RadioGroupLabel class="sr-only">{{
$t("type")
}}</RadioGroupLabel>
<div class="space-y-4">
<RadioGroupOption
v-for="[source, metadata] in optionsMetadataIter"
@@ -220,7 +228,7 @@
class="w-full sm:w-fit"
@click="() => performActionSource_wrapper()"
>
{{ createMode ? "Create" : "Save" }}
{{ createMode ? $t("create") : $t("save") }}
</LoadingButton>
<button
ref="cancelButtonRef"
@@ -233,7 +241,7 @@
}
"
>
Cancel
{{ $t("cancel") }}
</button>
</template>
</ModalTemplate>
@@ -268,6 +276,8 @@ definePageMeta({
layout: "admin",
});
const { t } = useI18n();
const sources = ref(
await $dropFetch<WorkingLibrarySource[]>("/api/v1/admin/library/sources"),
);
@@ -293,8 +303,7 @@ const optionsMetadata: {
};
} = {
Filesystem: {
description:
"Imports games from a path on disk. Requires version-based folder structure, and supports archived games.",
description: t("library.admin.sources.fsDesc"),
icon: DocumentIcon,
},
};
@@ -367,9 +376,11 @@ async function deleteSource(index: number) {
createModal(
ModalType.Notification,
{
title: "Failed to delete library source",
// @ts-expect-error attempt to display statusMessage on error
description: `Drop couldn't add delete this source: ${e?.statusMessage}`,
title: t("errors.library.source.delete.title"),
description: t("errors.library.source.delete.desc", [
// @ts-expect-error attempt to display statusMessage on error
e?.statusMessage ?? t("errors.unknown"),
]),
},
(_, c) => c(),
);