@cat-factory/app 0.45.3 → 0.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/layout/LanguageSwitcher.vue +54 -0
- package/app/components/layout/SideBar.vue +5 -1
- package/app/components/layout/TranslationWarningBanner.vue +69 -0
- package/app/pages/index.vue +2 -0
- package/app/plugins/locale.client.ts +20 -0
- package/app/stores/locale.ts +20 -0
- package/i18n/i18n.config.ts +36 -0
- package/i18n/locales/en.json +9 -0
- package/i18n/locales/es.json +71 -0
- package/i18n/locales/fr.json +71 -0
- package/i18n/locales/pl.json +71 -0
- package/i18n/locales/uk.json +71 -0
- package/nuxt.config.ts +7 -1
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { useLocaleStore } from '~/stores/locale'
|
|
5
|
+
|
|
6
|
+
// Language picker for the SPA's supported locales, shown at the sidebar bottom next to
|
|
7
|
+
// the user menu. The list is data-driven from the i18n config (`useI18n().locales`), so
|
|
8
|
+
// adding a locale in nuxt.config.ts surfaces it here automatically. Selecting one switches
|
|
9
|
+
// the live locale AND persists the choice (the locale store) so it survives a reload.
|
|
10
|
+
const { t, locale, locales, setLocale } = useI18n()
|
|
11
|
+
const localeStore = useLocaleStore()
|
|
12
|
+
|
|
13
|
+
const current = computed(
|
|
14
|
+
() => locales.value.find((l) => l.code === locale.value)?.name ?? locale.value,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// The typed-messages guard narrows the locale to the configured union, so take the same
|
|
18
|
+
// type setLocale expects rather than a bare string.
|
|
19
|
+
async function choose(code: typeof locale.value) {
|
|
20
|
+
if (code === locale.value) return
|
|
21
|
+
await setLocale(code)
|
|
22
|
+
localeStore.set(code)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const items = computed<DropdownMenuItem[][]>(() => [
|
|
26
|
+
locales.value.map((l) => ({
|
|
27
|
+
label: l.name ?? l.code,
|
|
28
|
+
icon: l.code === locale.value ? 'i-lucide-check' : undefined,
|
|
29
|
+
onSelect: () => {
|
|
30
|
+
void choose(l.code)
|
|
31
|
+
},
|
|
32
|
+
})),
|
|
33
|
+
])
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<UDropdownMenu :items="items" :content="{ side: 'top', align: 'start' }">
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
data-testid="language-switcher"
|
|
41
|
+
:aria-label="t('language.switcher')"
|
|
42
|
+
class="flex w-full items-center gap-2 rounded-lg border border-slate-800 bg-slate-900/60 p-2 text-left transition hover:bg-slate-800/60"
|
|
43
|
+
>
|
|
44
|
+
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-slate-400" />
|
|
45
|
+
<div class="min-w-0 flex-1">
|
|
46
|
+
<div class="truncate text-[10px] uppercase tracking-wide text-slate-500">
|
|
47
|
+
{{ t('language.switcher') }}
|
|
48
|
+
</div>
|
|
49
|
+
<div class="truncate text-xs font-medium text-white">{{ current }}</div>
|
|
50
|
+
</div>
|
|
51
|
+
<UIcon name="i-lucide-chevron-up" class="h-4 w-4 shrink-0 text-slate-500" />
|
|
52
|
+
</button>
|
|
53
|
+
</UDropdownMenu>
|
|
54
|
+
</template>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// default models).
|
|
8
8
|
import { useEventListener, useScrollLock } from '@vueuse/core'
|
|
9
9
|
import BoardSwitcher from '~/components/layout/BoardSwitcher.vue'
|
|
10
|
+
import LanguageSwitcher from '~/components/layout/LanguageSwitcher.vue'
|
|
10
11
|
import UserMenu from '~/components/auth/UserMenu.vue'
|
|
11
12
|
import { useViewport } from '~/composables/useViewport'
|
|
12
13
|
|
|
@@ -306,6 +307,9 @@ watch(
|
|
|
306
307
|
</section>
|
|
307
308
|
</div>
|
|
308
309
|
|
|
309
|
-
<
|
|
310
|
+
<div class="mt-auto space-y-2">
|
|
311
|
+
<LanguageSwitcher />
|
|
312
|
+
<UserMenu />
|
|
313
|
+
</div>
|
|
310
314
|
</aside>
|
|
311
315
|
</template>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
|
+
|
|
4
|
+
// Shown whenever the active locale is NOT English: the non-English catalogs are
|
|
5
|
+
// community/AI-provided and may be inaccurate, so warn the user and point them at the
|
|
6
|
+
// repository to report mistakes or open a fix PR. Rendered as a slim full-width strip at
|
|
7
|
+
// the very top (distinct from the centered config-warning cards below it, so they don't
|
|
8
|
+
// overlap). Dismissible per session; re-appears the next time the user switches locale.
|
|
9
|
+
const REPO_URL = 'https://github.com/kibertoad/cat-factory'
|
|
10
|
+
|
|
11
|
+
const { t, locale } = useI18n()
|
|
12
|
+
|
|
13
|
+
const dismissed = ref(false)
|
|
14
|
+
const show = computed(() => locale.value !== 'en' && !dismissed.value)
|
|
15
|
+
|
|
16
|
+
// A fresh switch is a new context for the warning, so un-dismiss on every locale change.
|
|
17
|
+
watch(locale, () => {
|
|
18
|
+
dismissed.value = false
|
|
19
|
+
})
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<Transition name="fade">
|
|
24
|
+
<div
|
|
25
|
+
v-if="show"
|
|
26
|
+
data-testid="translation-warning"
|
|
27
|
+
role="alert"
|
|
28
|
+
class="fixed inset-x-0 top-0 z-50 flex items-center gap-3 border-b border-amber-500/40 bg-amber-950/95 px-4 py-2 text-[13px] text-amber-100 shadow-lg backdrop-blur"
|
|
29
|
+
>
|
|
30
|
+
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-amber-400" />
|
|
31
|
+
<p class="min-w-0 flex-1">
|
|
32
|
+
<span class="font-semibold">{{ t('language.warning.title') }}</span>
|
|
33
|
+
<span class="mx-1.5 text-amber-400/60">·</span>
|
|
34
|
+
<i18n-t keypath="language.warning.body" tag="span" scope="global">
|
|
35
|
+
<template #repoLink>
|
|
36
|
+
<a
|
|
37
|
+
:href="REPO_URL"
|
|
38
|
+
target="_blank"
|
|
39
|
+
rel="noopener noreferrer"
|
|
40
|
+
class="inline-flex items-center gap-1 font-medium text-sky-300 hover:underline"
|
|
41
|
+
>
|
|
42
|
+
{{ t('language.warning.repoLinkLabel') }}
|
|
43
|
+
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
44
|
+
</a>
|
|
45
|
+
</template>
|
|
46
|
+
</i18n-t>
|
|
47
|
+
</p>
|
|
48
|
+
<UButton
|
|
49
|
+
color="neutral"
|
|
50
|
+
variant="ghost"
|
|
51
|
+
size="xs"
|
|
52
|
+
icon="i-lucide-x"
|
|
53
|
+
:aria-label="t('language.warning.dismiss')"
|
|
54
|
+
@click="dismissed = true"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</Transition>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style scoped>
|
|
61
|
+
.fade-enter-active,
|
|
62
|
+
.fade-leave-active {
|
|
63
|
+
transition: opacity 0.2s ease;
|
|
64
|
+
}
|
|
65
|
+
.fade-enter-from,
|
|
66
|
+
.fade-leave-to {
|
|
67
|
+
opacity: 0;
|
|
68
|
+
}
|
|
69
|
+
</style>
|
package/app/pages/index.vue
CHANGED
|
@@ -208,6 +208,8 @@ watch(
|
|
|
208
208
|
|
|
209
209
|
<template>
|
|
210
210
|
<div class="flex h-screen w-screen overflow-hidden bg-slate-950 text-slate-100">
|
|
211
|
+
<!-- Non-English locale warning (unofficial translation); slim strip above everything. -->
|
|
212
|
+
<TranslationWarningBanner />
|
|
211
213
|
<!-- Local-mode setup prompt (missing GitHub PAT); floats over whatever is shown below. -->
|
|
212
214
|
<GitHubPatBanner />
|
|
213
215
|
<!-- AI-readiness prompt (no usable model source, or default preset uses unavailable models). -->
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useLocaleStore } from '~/stores/locale'
|
|
2
|
+
|
|
3
|
+
// Restore the user's persisted language choice on boot. The app defaults to English
|
|
4
|
+
// (the locale store's default); this only re-applies an EXPLICIT prior pick. Kept
|
|
5
|
+
// client-only (the SPA renders client-side) and guarded against an unknown code so a
|
|
6
|
+
// stale/removed locale falls back to the i18n default instead of throwing.
|
|
7
|
+
export default defineNuxtPlugin(async (nuxtApp) => {
|
|
8
|
+
const i18n = nuxtApp.$i18n as {
|
|
9
|
+
locale: { value: string }
|
|
10
|
+
locales: { value: Array<{ code: string }> }
|
|
11
|
+
setLocale: (code: string) => Promise<void>
|
|
12
|
+
}
|
|
13
|
+
if (!i18n?.setLocale) return
|
|
14
|
+
|
|
15
|
+
const stored = useLocaleStore().current
|
|
16
|
+
const supported = i18n.locales.value.some((l) => l.code === stored)
|
|
17
|
+
if (supported && stored !== i18n.locale.value) {
|
|
18
|
+
await i18n.setLocale(stored)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
// Persists the user's EXPLICIT language choice so it survives reloads. The app always
|
|
5
|
+
// boots in English (the `current` default) — there is no browser auto-detect — and only
|
|
6
|
+
// an explicit pick via the switcher changes this. A client plugin applies `current` to
|
|
7
|
+
// the active i18n locale on startup; the switcher writes here AND calls i18n's setLocale.
|
|
8
|
+
export const useLocaleStore = defineStore(
|
|
9
|
+
'locale',
|
|
10
|
+
() => {
|
|
11
|
+
const current = ref('en')
|
|
12
|
+
|
|
13
|
+
function set(code: string) {
|
|
14
|
+
current.value = code
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return { current, set }
|
|
18
|
+
},
|
|
19
|
+
{ persist: { pick: ['current'] } },
|
|
20
|
+
)
|
package/i18n/i18n.config.ts
CHANGED
|
@@ -19,11 +19,47 @@ export default defineI18nConfig(() => ({
|
|
|
19
19
|
currency: { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' },
|
|
20
20
|
percent: { style: 'percent', maximumFractionDigits: 1 },
|
|
21
21
|
},
|
|
22
|
+
es: {
|
|
23
|
+
decimal: { style: 'decimal' },
|
|
24
|
+
currency: { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' },
|
|
25
|
+
percent: { style: 'percent', maximumFractionDigits: 1 },
|
|
26
|
+
},
|
|
27
|
+
pl: {
|
|
28
|
+
decimal: { style: 'decimal' },
|
|
29
|
+
currency: { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' },
|
|
30
|
+
percent: { style: 'percent', maximumFractionDigits: 1 },
|
|
31
|
+
},
|
|
32
|
+
uk: {
|
|
33
|
+
decimal: { style: 'decimal' },
|
|
34
|
+
currency: { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' },
|
|
35
|
+
percent: { style: 'percent', maximumFractionDigits: 1 },
|
|
36
|
+
},
|
|
37
|
+
fr: {
|
|
38
|
+
decimal: { style: 'decimal' },
|
|
39
|
+
currency: { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' },
|
|
40
|
+
percent: { style: 'percent', maximumFractionDigits: 1 },
|
|
41
|
+
},
|
|
22
42
|
},
|
|
23
43
|
datetimeFormats: {
|
|
24
44
|
en: {
|
|
25
45
|
short: { dateStyle: 'medium' },
|
|
26
46
|
long: { dateStyle: 'long', timeStyle: 'short' },
|
|
27
47
|
},
|
|
48
|
+
es: {
|
|
49
|
+
short: { dateStyle: 'medium' },
|
|
50
|
+
long: { dateStyle: 'long', timeStyle: 'short' },
|
|
51
|
+
},
|
|
52
|
+
pl: {
|
|
53
|
+
short: { dateStyle: 'medium' },
|
|
54
|
+
long: { dateStyle: 'long', timeStyle: 'short' },
|
|
55
|
+
},
|
|
56
|
+
uk: {
|
|
57
|
+
short: { dateStyle: 'medium' },
|
|
58
|
+
long: { dateStyle: 'long', timeStyle: 'short' },
|
|
59
|
+
},
|
|
60
|
+
fr: {
|
|
61
|
+
short: { dateStyle: 'medium' },
|
|
62
|
+
long: { dateStyle: 'long', timeStyle: 'short' },
|
|
63
|
+
},
|
|
28
64
|
},
|
|
29
65
|
}))
|
package/i18n/locales/en.json
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
+
"language": {
|
|
3
|
+
"switcher": "Language",
|
|
4
|
+
"warning": {
|
|
5
|
+
"title": "Unofficial translation",
|
|
6
|
+
"body": "This translation is community-provided and may be inaccurate. Spotted a mistake? Please report it or open a fix on {repoLink}.",
|
|
7
|
+
"repoLinkLabel": "the cat-factory repository",
|
|
8
|
+
"dismiss": "Dismiss"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
2
11
|
"common": {
|
|
3
12
|
"save": "Save",
|
|
4
13
|
"cancel": "Cancel",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"language": {
|
|
3
|
+
"switcher": "Idioma",
|
|
4
|
+
"warning": {
|
|
5
|
+
"title": "Traducción no oficial",
|
|
6
|
+
"body": "Esta traducción es proporcionada por la comunidad y puede contener errores. ¿Has encontrado un error? Repórtalo o envía una corrección en {repoLink}.",
|
|
7
|
+
"repoLinkLabel": "el repositorio de cat-factory",
|
|
8
|
+
"dismiss": "Descartar"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"common": {
|
|
12
|
+
"save": "Guardar",
|
|
13
|
+
"cancel": "Cancelar",
|
|
14
|
+
"retry": "Reintentar",
|
|
15
|
+
"actionFailed": "La acción falló",
|
|
16
|
+
"close": "Cerrar"
|
|
17
|
+
},
|
|
18
|
+
"nav": {
|
|
19
|
+
"menu": "Menú de navegación",
|
|
20
|
+
"openMenu": "Abrir menú",
|
|
21
|
+
"closeMenu": "Cerrar menú",
|
|
22
|
+
"commandBar": "Buscar o ejecutar un comando…",
|
|
23
|
+
"create": "Crear",
|
|
24
|
+
"buildPipeline": "Crear una canalización",
|
|
25
|
+
"repositories": "Repositorios",
|
|
26
|
+
"addFromRepo": "Añadir desde un repositorio existente",
|
|
27
|
+
"bootstrapRepo": "Inicializar repositorio",
|
|
28
|
+
"integrations": "Integraciones",
|
|
29
|
+
"sandbox": "Entorno de pruebas",
|
|
30
|
+
"kaizen": "Kaizen",
|
|
31
|
+
"workspaceContext": "Contexto del espacio de trabajo",
|
|
32
|
+
"contextFragments": "Fragmentos de contexto",
|
|
33
|
+
"configuration": "Configuración",
|
|
34
|
+
"workspaceSettings": "Ajustes del espacio de trabajo",
|
|
35
|
+
"modelConfiguration": "Configuración del modelo",
|
|
36
|
+
"accountSettings": "Ajustes de la cuenta"
|
|
37
|
+
},
|
|
38
|
+
"board": {
|
|
39
|
+
"toolbar": {
|
|
40
|
+
"addService": "Añadir servicio",
|
|
41
|
+
"decisionWord": "decisión | decisiones"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"errors": {
|
|
45
|
+
"action": {
|
|
46
|
+
"retryFailed": "El reintento falló",
|
|
47
|
+
"startFailed": "No se pudo iniciar",
|
|
48
|
+
"mergeFailed": "No se pudo fusionar",
|
|
49
|
+
"restartFailed": "No se pudo reiniciar"
|
|
50
|
+
},
|
|
51
|
+
"conflict": {
|
|
52
|
+
"title": {
|
|
53
|
+
"dependencies_unmet": "Bloqueado por dependencias",
|
|
54
|
+
"task_limit_reached": "Límite de concurrencia alcanzado",
|
|
55
|
+
"tester_infra_unsupported": "Infraestructura de pruebas no configurada",
|
|
56
|
+
"agent_backend_unconfigured": "Backend del agente no configurado",
|
|
57
|
+
"run_not_retryable": "La ejecución no se puede reintentar",
|
|
58
|
+
"no_pr_to_merge": "No hay PR para fusionar",
|
|
59
|
+
"github_not_connected": "GitHub no conectado",
|
|
60
|
+
"bootstrap_not_retryable": "La inicialización no se puede reintentar",
|
|
61
|
+
"bootstrap_reference_missing": "La arquitectura de referencia ha desaparecido"
|
|
62
|
+
},
|
|
63
|
+
"fallbackMessage": "Esta acción entra en conflicto con el estado actual.",
|
|
64
|
+
"providersUnconfigured": {
|
|
65
|
+
"title": "No hay proveedor de IA para este modelo",
|
|
66
|
+
"body": "No hay ningún proveedor configurado para {models}. Añade una clave de proveedor, conecta una suscripción o activa Cloudflare AI para ejecutarlo.",
|
|
67
|
+
"action": "Configurar IA"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"language": {
|
|
3
|
+
"switcher": "Langue",
|
|
4
|
+
"warning": {
|
|
5
|
+
"title": "Traduction non officielle",
|
|
6
|
+
"body": "Cette traduction est fournie par la communauté et peut être inexacte. Vous avez repéré une erreur ? Signalez-la ou proposez une correction sur {repoLink}.",
|
|
7
|
+
"repoLinkLabel": "le dépôt cat-factory",
|
|
8
|
+
"dismiss": "Fermer"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"common": {
|
|
12
|
+
"save": "Enregistrer",
|
|
13
|
+
"cancel": "Annuler",
|
|
14
|
+
"retry": "Réessayer",
|
|
15
|
+
"actionFailed": "Échec de l’action",
|
|
16
|
+
"close": "Fermer"
|
|
17
|
+
},
|
|
18
|
+
"nav": {
|
|
19
|
+
"menu": "Menu de navigation",
|
|
20
|
+
"openMenu": "Ouvrir le menu",
|
|
21
|
+
"closeMenu": "Fermer le menu",
|
|
22
|
+
"commandBar": "Rechercher ou exécuter une commande…",
|
|
23
|
+
"create": "Créer",
|
|
24
|
+
"buildPipeline": "Créer un pipeline",
|
|
25
|
+
"repositories": "Dépôts",
|
|
26
|
+
"addFromRepo": "Ajouter depuis un dépôt existant",
|
|
27
|
+
"bootstrapRepo": "Initialiser un dépôt",
|
|
28
|
+
"integrations": "Intégrations",
|
|
29
|
+
"sandbox": "Bac à sable",
|
|
30
|
+
"kaizen": "Kaizen",
|
|
31
|
+
"workspaceContext": "Contexte de l’espace de travail",
|
|
32
|
+
"contextFragments": "Fragments de contexte",
|
|
33
|
+
"configuration": "Configuration",
|
|
34
|
+
"workspaceSettings": "Paramètres de l’espace de travail",
|
|
35
|
+
"modelConfiguration": "Configuration du modèle",
|
|
36
|
+
"accountSettings": "Paramètres du compte"
|
|
37
|
+
},
|
|
38
|
+
"board": {
|
|
39
|
+
"toolbar": {
|
|
40
|
+
"addService": "Ajouter un service",
|
|
41
|
+
"decisionWord": "décision | décisions"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"errors": {
|
|
45
|
+
"action": {
|
|
46
|
+
"retryFailed": "Échec de la nouvelle tentative",
|
|
47
|
+
"startFailed": "Échec du démarrage",
|
|
48
|
+
"mergeFailed": "Échec de la fusion",
|
|
49
|
+
"restartFailed": "Échec du redémarrage"
|
|
50
|
+
},
|
|
51
|
+
"conflict": {
|
|
52
|
+
"title": {
|
|
53
|
+
"dependencies_unmet": "Bloqué par des dépendances",
|
|
54
|
+
"task_limit_reached": "Limite de concurrence atteinte",
|
|
55
|
+
"tester_infra_unsupported": "Infrastructure de test non configurée",
|
|
56
|
+
"agent_backend_unconfigured": "Backend de l’agent non configuré",
|
|
57
|
+
"run_not_retryable": "L’exécution ne peut pas être relancée",
|
|
58
|
+
"no_pr_to_merge": "Aucune PR à fusionner",
|
|
59
|
+
"github_not_connected": "GitHub non connecté",
|
|
60
|
+
"bootstrap_not_retryable": "L’initialisation ne peut pas être relancée",
|
|
61
|
+
"bootstrap_reference_missing": "L’architecture de référence a disparu"
|
|
62
|
+
},
|
|
63
|
+
"fallbackMessage": "Cette action est en conflit avec l’état actuel.",
|
|
64
|
+
"providersUnconfigured": {
|
|
65
|
+
"title": "Aucun fournisseur d’IA pour ce modèle",
|
|
66
|
+
"body": "Aucun fournisseur n’est configuré pour {models}. Ajoutez une clé de fournisseur, connectez un abonnement ou activez Cloudflare AI pour l’exécuter.",
|
|
67
|
+
"action": "Configurer l’IA"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"language": {
|
|
3
|
+
"switcher": "Język",
|
|
4
|
+
"warning": {
|
|
5
|
+
"title": "Nieoficjalne tłumaczenie",
|
|
6
|
+
"body": "To tłumaczenie pochodzi od społeczności i może być niedokładne. Zauważyłeś błąd? Zgłoś go lub prześlij poprawkę w {repoLink}.",
|
|
7
|
+
"repoLinkLabel": "repozytorium cat-factory",
|
|
8
|
+
"dismiss": "Odrzuć"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"common": {
|
|
12
|
+
"save": "Zapisz",
|
|
13
|
+
"cancel": "Anuluj",
|
|
14
|
+
"retry": "Ponów",
|
|
15
|
+
"actionFailed": "Akcja nie powiodła się",
|
|
16
|
+
"close": "Zamknij"
|
|
17
|
+
},
|
|
18
|
+
"nav": {
|
|
19
|
+
"menu": "Menu nawigacji",
|
|
20
|
+
"openMenu": "Otwórz menu",
|
|
21
|
+
"closeMenu": "Zamknij menu",
|
|
22
|
+
"commandBar": "Wyszukaj lub uruchom polecenie…",
|
|
23
|
+
"create": "Utwórz",
|
|
24
|
+
"buildPipeline": "Zbuduj potok",
|
|
25
|
+
"repositories": "Repozytoria",
|
|
26
|
+
"addFromRepo": "Dodaj z istniejącego repozytorium",
|
|
27
|
+
"bootstrapRepo": "Zainicjuj repozytorium",
|
|
28
|
+
"integrations": "Integracje",
|
|
29
|
+
"sandbox": "Piaskownica",
|
|
30
|
+
"kaizen": "Kaizen",
|
|
31
|
+
"workspaceContext": "Kontekst obszaru roboczego",
|
|
32
|
+
"contextFragments": "Fragmenty kontekstu",
|
|
33
|
+
"configuration": "Konfiguracja",
|
|
34
|
+
"workspaceSettings": "Ustawienia obszaru roboczego",
|
|
35
|
+
"modelConfiguration": "Konfiguracja modelu",
|
|
36
|
+
"accountSettings": "Ustawienia konta"
|
|
37
|
+
},
|
|
38
|
+
"board": {
|
|
39
|
+
"toolbar": {
|
|
40
|
+
"addService": "Dodaj usługę",
|
|
41
|
+
"decisionWord": "decyzja | decyzje | decyzji"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"errors": {
|
|
45
|
+
"action": {
|
|
46
|
+
"retryFailed": "Ponowienie nie powiodło się",
|
|
47
|
+
"startFailed": "Nie udało się uruchomić",
|
|
48
|
+
"mergeFailed": "Nie udało się scalić",
|
|
49
|
+
"restartFailed": "Nie udało się ponownie uruchomić"
|
|
50
|
+
},
|
|
51
|
+
"conflict": {
|
|
52
|
+
"title": {
|
|
53
|
+
"dependencies_unmet": "Zablokowane przez zależności",
|
|
54
|
+
"task_limit_reached": "Osiągnięto limit współbieżności",
|
|
55
|
+
"tester_infra_unsupported": "Infrastruktura testowa nie jest skonfigurowana",
|
|
56
|
+
"agent_backend_unconfigured": "Backend agenta nie jest skonfigurowany",
|
|
57
|
+
"run_not_retryable": "Uruchomienia nie można ponowić",
|
|
58
|
+
"no_pr_to_merge": "Brak PR do scalenia",
|
|
59
|
+
"github_not_connected": "GitHub nie jest połączony",
|
|
60
|
+
"bootstrap_not_retryable": "Inicjalizacji nie można ponowić",
|
|
61
|
+
"bootstrap_reference_missing": "Architektura referencyjna zniknęła"
|
|
62
|
+
},
|
|
63
|
+
"fallbackMessage": "Ta akcja jest sprzeczna z bieżącym stanem.",
|
|
64
|
+
"providersUnconfigured": {
|
|
65
|
+
"title": "Brak dostawcy AI dla tego modelu",
|
|
66
|
+
"body": "Dla {models} nie skonfigurowano żadnego dostawcy. Dodaj klucz dostawcy, połącz subskrypcję lub włącz Cloudflare AI, aby go uruchomić.",
|
|
67
|
+
"action": "Skonfiguruj AI"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"language": {
|
|
3
|
+
"switcher": "Мова",
|
|
4
|
+
"warning": {
|
|
5
|
+
"title": "Неофіційний переклад",
|
|
6
|
+
"body": "Цей переклад надано спільнотою та може бути неточним. Помітили помилку? Повідомте про неї або надішліть виправлення у {repoLink}.",
|
|
7
|
+
"repoLinkLabel": "репозиторії cat-factory",
|
|
8
|
+
"dismiss": "Закрити"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"common": {
|
|
12
|
+
"save": "Зберегти",
|
|
13
|
+
"cancel": "Скасувати",
|
|
14
|
+
"retry": "Повторити",
|
|
15
|
+
"actionFailed": "Не вдалося виконати дію",
|
|
16
|
+
"close": "Закрити"
|
|
17
|
+
},
|
|
18
|
+
"nav": {
|
|
19
|
+
"menu": "Меню навігації",
|
|
20
|
+
"openMenu": "Відкрити меню",
|
|
21
|
+
"closeMenu": "Закрити меню",
|
|
22
|
+
"commandBar": "Знайти або виконати команду…",
|
|
23
|
+
"create": "Створити",
|
|
24
|
+
"buildPipeline": "Створити конвеєр",
|
|
25
|
+
"repositories": "Репозиторії",
|
|
26
|
+
"addFromRepo": "Додати з наявного репозиторію",
|
|
27
|
+
"bootstrapRepo": "Ініціалізувати репозиторій",
|
|
28
|
+
"integrations": "Інтеграції",
|
|
29
|
+
"sandbox": "Пісочниця",
|
|
30
|
+
"kaizen": "Kaizen",
|
|
31
|
+
"workspaceContext": "Контекст робочого простору",
|
|
32
|
+
"contextFragments": "Фрагменти контексту",
|
|
33
|
+
"configuration": "Конфігурація",
|
|
34
|
+
"workspaceSettings": "Налаштування робочого простору",
|
|
35
|
+
"modelConfiguration": "Конфігурація моделі",
|
|
36
|
+
"accountSettings": "Налаштування облікового запису"
|
|
37
|
+
},
|
|
38
|
+
"board": {
|
|
39
|
+
"toolbar": {
|
|
40
|
+
"addService": "Додати сервіс",
|
|
41
|
+
"decisionWord": "рішення | рішення | рішень"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"errors": {
|
|
45
|
+
"action": {
|
|
46
|
+
"retryFailed": "Не вдалося повторити",
|
|
47
|
+
"startFailed": "Не вдалося запустити",
|
|
48
|
+
"mergeFailed": "Не вдалося злити",
|
|
49
|
+
"restartFailed": "Не вдалося перезапустити"
|
|
50
|
+
},
|
|
51
|
+
"conflict": {
|
|
52
|
+
"title": {
|
|
53
|
+
"dependencies_unmet": "Заблоковано залежностями",
|
|
54
|
+
"task_limit_reached": "Досягнуто ліміту одночасності",
|
|
55
|
+
"tester_infra_unsupported": "Тестову інфраструктуру не налаштовано",
|
|
56
|
+
"agent_backend_unconfigured": "Бекенд агента не налаштовано",
|
|
57
|
+
"run_not_retryable": "Запуск неможливо повторити",
|
|
58
|
+
"no_pr_to_merge": "Немає PR для злиття",
|
|
59
|
+
"github_not_connected": "GitHub не підключено",
|
|
60
|
+
"bootstrap_not_retryable": "Ініціалізацію неможливо повторити",
|
|
61
|
+
"bootstrap_reference_missing": "Еталонна архітектура зникла"
|
|
62
|
+
},
|
|
63
|
+
"fallbackMessage": "Ця дія суперечить поточному стану.",
|
|
64
|
+
"providersUnconfigured": {
|
|
65
|
+
"title": "Немає постачальника ШІ для цієї моделі",
|
|
66
|
+
"body": "Для {models} не налаштовано жодного постачальника. Додайте ключ постачальника, підключіть підписку або увімкніть Cloudflare AI, щоб запустити її.",
|
|
67
|
+
"action": "Налаштувати ШІ"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
package/nuxt.config.ts
CHANGED
|
@@ -46,7 +46,13 @@ export default defineNuxtConfig({
|
|
|
46
46
|
// Pure SPA (`ssr: false`): a single in-app locale, no URL-prefix routing.
|
|
47
47
|
strategy: 'no_prefix',
|
|
48
48
|
defaultLocale: 'en',
|
|
49
|
-
locales: [
|
|
49
|
+
locales: [
|
|
50
|
+
{ code: 'en', language: 'en-US', file: 'en.json', name: 'English' },
|
|
51
|
+
{ code: 'es', language: 'es-ES', file: 'es.json', name: 'Español' },
|
|
52
|
+
{ code: 'pl', language: 'pl-PL', file: 'pl.json', name: 'Polski' },
|
|
53
|
+
{ code: 'uk', language: 'uk-UA', file: 'uk.json', name: 'Українська' },
|
|
54
|
+
{ code: 'fr', language: 'fr-FR', file: 'fr.json', name: 'Français' },
|
|
55
|
+
],
|
|
50
56
|
vueI18n: 'i18n.config.ts',
|
|
51
57
|
experimental: {
|
|
52
58
|
// Generate types from the `en` messages so an unknown `$t`/`t` key is a `nuxt
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|