feat(i18n): add Phase 3 observability translations (EN + PL)

Added translations for all observability components:
- Validation warnings panel
- Auto-fixes badge
- AI reasoning process viewer
- Debug information panel
- Structured error display

English translations (en.json):
- observability_validationWarnings: "Validation Warnings"
- observability_autoFixesApplied: "Automatically adjusted"
- observability_aiReasoningProcess: "AI Reasoning Process"
- observability_debugInfo: "Debug Information"
- observability_model/duration/tokenUsage: Debug panel labels
- observability_validationFailed: "Safety validation failed"

Polish translations (pl.json):
- observability_validationWarnings: "Ostrzeżenia walidacji"
- observability_autoFixesApplied: "Automatycznie dostosowano"
- observability_aiReasoningProcess: "Proces rozumowania AI"
- observability_debugInfo: "Informacje debugowania"
- All debug panel labels translated
- observability_validationFailed: "Walidacja bezpieczeństwa nie powiodła się"

Updated components:
- ValidationWarningsAlert: Uses m.observability_validationWarnings()
- AutoFixBadge: Uses m.observability_autoFixesApplied()
- ReasoningChainViewer: Uses m.observability_aiReasoningProcess()
- MetadataDebugPanel: All labels now use i18n
- StructuredErrorDisplay: Translates error prefixes

All components now fully support English and Polish locales.
This commit is contained in:
Piotr Oleszczyk 2026-03-06 16:28:23 +01:00
parent b2886c2f2b
commit d228b44209
7 changed files with 64 additions and 13 deletions

View file

@ -216,6 +216,21 @@
"suggest_summaryConstraints": "Constraints", "suggest_summaryConstraints": "Constraints",
"suggest_stepOptionalBadge": "optional", "suggest_stepOptionalBadge": "optional",
"observability_validationWarnings": "Validation Warnings",
"observability_showMore": "Show {count} more",
"observability_showLess": "Show less",
"observability_autoFixesApplied": "Automatically adjusted",
"observability_aiReasoningProcess": "AI Reasoning Process",
"observability_debugInfo": "Debug Information",
"observability_model": "Model",
"observability_duration": "Duration",
"observability_tokenUsage": "Token Usage",
"observability_tokenPrompt": "Prompt",
"observability_tokenCompletion": "Completion",
"observability_tokenThinking": "Thinking",
"observability_tokenTotal": "Total",
"observability_validationFailed": "Safety validation failed",
"medications_title": "Medications", "medications_title": "Medications",
"medications_count": [ "medications_count": [
{ {

View file

@ -222,6 +222,21 @@
"suggest_summaryConstraints": "Ograniczenia", "suggest_summaryConstraints": "Ograniczenia",
"suggest_stepOptionalBadge": "opcjonalny", "suggest_stepOptionalBadge": "opcjonalny",
"observability_validationWarnings": "Ostrzeżenia walidacji",
"observability_showMore": "Pokaż {count} więcej",
"observability_showLess": "Pokaż mniej",
"observability_autoFixesApplied": "Automatycznie dostosowano",
"observability_aiReasoningProcess": "Proces rozumowania AI",
"observability_debugInfo": "Informacje debugowania",
"observability_model": "Model",
"observability_duration": "Czas trwania",
"observability_tokenUsage": "Użycie tokenów",
"observability_tokenPrompt": "Prompt",
"observability_tokenCompletion": "Odpowiedź",
"observability_tokenThinking": "Myślenie",
"observability_tokenTotal": "Razem",
"observability_validationFailed": "Walidacja bezpieczeństwa nie powiodła się",
"medications_title": "Leki", "medications_title": "Leki",
"medications_count": [ "medications_count": [
{ {

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Sparkles } from 'lucide-svelte'; import { Sparkles } from 'lucide-svelte';
import { m } from '$lib/paraglide/messages.js';
interface Props { interface Props {
autoFixes: string[]; autoFixes: string[];
@ -13,7 +14,7 @@
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
<Sparkles class="size-5 shrink-0 mt-0.5" /> <Sparkles class="size-5 shrink-0 mt-0.5" />
<div class="flex-1"> <div class="flex-1">
<p class="font-medium mb-1">Automatically adjusted</p> <p class="font-medium mb-1">{m.observability_autoFixesApplied()}</p>
<ul class="list-disc list-inside space-y-1 text-sm"> <ul class="list-disc list-inside space-y-1 text-sm">
{#each autoFixes as fix} {#each autoFixes as fix}
<li>{fix}</li> <li>{fix}</li>

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Info, ChevronDown, ChevronRight } from 'lucide-svelte'; import { Info, ChevronDown, ChevronRight } from 'lucide-svelte';
import { m } from '$lib/paraglide/messages.js';
import type { ResponseMetadata } from '$lib/types'; import type { ResponseMetadata } from '$lib/types';
interface Props { interface Props {
@ -23,7 +24,7 @@
class="w-full flex items-center gap-2 px-4 py-3 bg-muted/30 hover:bg-muted/50 transition-colors" class="w-full flex items-center gap-2 px-4 py-3 bg-muted/30 hover:bg-muted/50 transition-colors"
> >
<Info class="size-4 text-muted-foreground" /> <Info class="size-4 text-muted-foreground" />
<span class="text-sm font-medium text-foreground">Debug Information</span> <span class="text-sm font-medium text-foreground">{m.observability_debugInfo()}</span>
<div class="ml-auto"> <div class="ml-auto">
{#if expanded} {#if expanded}
<ChevronDown class="size-4 text-muted-foreground" /> <ChevronDown class="size-4 text-muted-foreground" />
@ -36,39 +37,39 @@
<div class="p-4 bg-card border-t border-muted"> <div class="p-4 bg-card border-t border-muted">
<dl class="grid grid-cols-1 gap-3 text-sm"> <dl class="grid grid-cols-1 gap-3 text-sm">
<div> <div>
<dt class="font-medium text-foreground">Model</dt> <dt class="font-medium text-foreground">{m.observability_model()}</dt>
<dd class="text-muted-foreground font-mono text-xs mt-0.5">{metadata.model_used}</dd> <dd class="text-muted-foreground font-mono text-xs mt-0.5">{metadata.model_used}</dd>
</div> </div>
<div> <div>
<dt class="font-medium text-foreground">Duration</dt> <dt class="font-medium text-foreground">{m.observability_duration()}</dt>
<dd class="text-muted-foreground">{formatNumber(metadata.duration_ms)} ms</dd> <dd class="text-muted-foreground">{formatNumber(metadata.duration_ms)} ms</dd>
</div> </div>
{#if metadata.token_metrics} {#if metadata.token_metrics}
<div> <div>
<dt class="font-medium text-foreground">Token Usage</dt> <dt class="font-medium text-foreground">{m.observability_tokenUsage()}</dt>
<dd class="text-muted-foreground space-y-1 mt-0.5"> <dd class="text-muted-foreground space-y-1 mt-0.5">
<div class="flex justify-between"> <div class="flex justify-between">
<span>Prompt:</span> <span>{m.observability_tokenPrompt()}:</span>
<span class="font-mono text-xs" <span class="font-mono text-xs"
>{formatNumber(metadata.token_metrics.prompt_tokens)}</span >{formatNumber(metadata.token_metrics.prompt_tokens)}</span
> >
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span>Completion:</span> <span>{m.observability_tokenCompletion()}:</span>
<span class="font-mono text-xs" <span class="font-mono text-xs"
>{formatNumber(metadata.token_metrics.completion_tokens)}</span >{formatNumber(metadata.token_metrics.completion_tokens)}</span
> >
</div> </div>
{#if metadata.token_metrics.thoughts_tokens} {#if metadata.token_metrics.thoughts_tokens}
<div class="flex justify-between"> <div class="flex justify-between">
<span>Thinking:</span> <span>{m.observability_tokenThinking()}:</span>
<span class="font-mono text-xs" <span class="font-mono text-xs"
>{formatNumber(metadata.token_metrics.thoughts_tokens)}</span >{formatNumber(metadata.token_metrics.thoughts_tokens)}</span
> >
</div> </div>
{/if} {/if}
<div class="flex justify-between font-medium border-t border-muted pt-1 mt-1"> <div class="flex justify-between font-medium border-t border-muted pt-1 mt-1">
<span>Total:</span> <span>{m.observability_tokenTotal()}:</span>
<span class="font-mono text-xs" <span class="font-mono text-xs"
>{formatNumber(metadata.token_metrics.total_tokens)}</span >{formatNumber(metadata.token_metrics.total_tokens)}</span
> >

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Brain, ChevronDown, ChevronRight } from 'lucide-svelte'; import { Brain, ChevronDown, ChevronRight } from 'lucide-svelte';
import { m } from '$lib/paraglide/messages.js';
interface Props { interface Props {
reasoningChain?: string; reasoningChain?: string;
@ -18,7 +19,7 @@
class="w-full flex items-center gap-2 px-4 py-3 bg-muted/30 hover:bg-muted/50 transition-colors" class="w-full flex items-center gap-2 px-4 py-3 bg-muted/30 hover:bg-muted/50 transition-colors"
> >
<Brain class="size-4 text-muted-foreground" /> <Brain class="size-4 text-muted-foreground" />
<span class="text-sm font-medium text-foreground">AI Reasoning Process</span> <span class="text-sm font-medium text-foreground">{m.observability_aiReasoningProcess()}</span>
<div class="ml-auto"> <div class="ml-auto">
{#if expanded} {#if expanded}
<ChevronDown class="size-4 text-muted-foreground" /> <ChevronDown class="size-4 text-muted-foreground" />

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { XCircle } from 'lucide-svelte'; import { XCircle } from 'lucide-svelte';
import { m } from '$lib/paraglide/messages.js';
interface Props { interface Props {
error: string; error: string;
@ -25,6 +26,20 @@
const cleanedErrors = $derived( const cleanedErrors = $derived(
hasPrefix && prefix ? [errors[0].substring(prefix.length)] : errors hasPrefix && prefix ? [errors[0].substring(prefix.length)] : errors
); );
// Translate known error prefixes
const translatedPrefix = $derived(() => {
if (!prefix) return '';
const prefixText = prefix.replace(':', '').trim();
// Check for common validation failure prefix
if (
prefixText.includes('safety validation') ||
prefixText.includes('validation')
) {
return m.observability_validationFailed();
}
return prefixText;
});
</script> </script>
<div class="editorial-alert editorial-alert--error"> <div class="editorial-alert editorial-alert--error">
@ -32,7 +47,7 @@
<XCircle class="size-5 shrink-0 mt-0.5" /> <XCircle class="size-5 shrink-0 mt-0.5" />
<div class="flex-1"> <div class="flex-1">
{#if prefix} {#if prefix}
<p class="font-medium mb-2">{prefix.replace(':', '')}</p> <p class="font-medium mb-2">{translatedPrefix()}</p>
{/if} {/if}
{#if cleanedErrors.length === 1} {#if cleanedErrors.length === 1}
<p>{cleanedErrors[0]}</p> <p>{cleanedErrors[0]}</p>

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { AlertTriangle } from 'lucide-svelte'; import { AlertTriangle } from 'lucide-svelte';
import { m } from '$lib/paraglide/messages.js';
interface Props { interface Props {
warnings: string[]; warnings: string[];
@ -19,7 +20,7 @@
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
<AlertTriangle class="size-5 shrink-0 mt-0.5" /> <AlertTriangle class="size-5 shrink-0 mt-0.5" />
<div class="flex-1"> <div class="flex-1">
<p class="font-medium mb-1">Validation Warnings</p> <p class="font-medium mb-1">{m.observability_validationWarnings()}</p>
<ul class="list-disc list-inside space-y-1 text-sm"> <ul class="list-disc list-inside space-y-1 text-sm">
{#each displayedWarnings as warning} {#each displayedWarnings as warning}
<li>{warning}</li> <li>{warning}</li>
@ -31,7 +32,9 @@
onclick={() => (expanded = !expanded)} onclick={() => (expanded = !expanded)}
class="text-sm underline mt-2 hover:no-underline" class="text-sm underline mt-2 hover:no-underline"
> >
{expanded ? 'Show less' : `Show ${warnings.length - 3} more`} {expanded
? m.observability_showLess()
: m.observability_showMore({ count: warnings.length - 3 })}
</button> </button>
{/if} {/if}
</div> </div>