feat: use i18n in components
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="ru">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
import SelectField from './ui/SelectField.svelte';
|
import SelectField from './ui/SelectField.svelte';
|
||||||
import SliderField from './ui/SliderField.svelte';
|
import SliderField from './ui/SliderField.svelte';
|
||||||
import TextField from './ui/TextField.svelte';
|
import TextField from './ui/TextField.svelte';
|
||||||
import type { ParamDef } from '$lib/registry';
|
import type { ParamDef, ToolEntry } from '$lib/registry';
|
||||||
|
import { optionLabel, paramLabel } from '$lib/i18n/tool-strings';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
tool: ToolEntry;
|
||||||
params: ParamDef[];
|
params: ParamDef[];
|
||||||
values: Record<string, any>;
|
values: Record<string, any>;
|
||||||
pipetteTargetId?: string | null;
|
pipetteTargetId?: string | null;
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
tool,
|
||||||
params,
|
params,
|
||||||
values = $bindable(),
|
values = $bindable(),
|
||||||
pipetteTargetId = null,
|
pipetteTargetId = null,
|
||||||
@@ -33,11 +36,11 @@
|
|||||||
{#each params as param (param.id)}
|
{#each params as param (param.id)}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
{#if param.type === 'checkbox'}
|
{#if param.type === 'checkbox'}
|
||||||
<CheckboxField id={param.id} label={param.label} bind:checked={values[param.id]} />
|
<CheckboxField id={param.id} label={paramLabel(tool, param)} bind:checked={values[param.id]} />
|
||||||
{:else if param.type === 'number'}
|
{:else if param.type === 'number'}
|
||||||
<TextField
|
<TextField
|
||||||
id={param.id}
|
id={param.id}
|
||||||
label={param.label}
|
label={paramLabel(tool, param)}
|
||||||
type="number"
|
type="number"
|
||||||
min={param.min}
|
min={param.min}
|
||||||
max={param.max}
|
max={param.max}
|
||||||
@@ -47,7 +50,7 @@
|
|||||||
{:else if param.type === 'slider'}
|
{:else if param.type === 'slider'}
|
||||||
<SliderField
|
<SliderField
|
||||||
id={param.id}
|
id={param.id}
|
||||||
label={param.label}
|
label={paramLabel(tool, param)}
|
||||||
min={param.min}
|
min={param.min}
|
||||||
max={param.max}
|
max={param.max}
|
||||||
step={param.step}
|
step={param.step}
|
||||||
@@ -57,14 +60,17 @@
|
|||||||
{:else if param.type === 'select'}
|
{:else if param.type === 'select'}
|
||||||
<SelectField
|
<SelectField
|
||||||
id={param.id}
|
id={param.id}
|
||||||
label={param.label}
|
label={paramLabel(tool, param)}
|
||||||
options={param.options}
|
options={param.options.map((o) => ({
|
||||||
|
value: o.value,
|
||||||
|
label: optionLabel(tool, param, o.value)
|
||||||
|
}))}
|
||||||
bind:value={values[param.id]}
|
bind:value={values[param.id]}
|
||||||
/>
|
/>
|
||||||
{:else if param.type === 'color'}
|
{:else if param.type === 'color'}
|
||||||
<ColorField
|
<ColorField
|
||||||
id={param.id}
|
id={param.id}
|
||||||
label={param.label}
|
label={paramLabel(tool, param)}
|
||||||
bind:value={values[param.id]}
|
bind:value={values[param.id]}
|
||||||
pipetteActive={pipetteTargetId === param.id}
|
pipetteActive={pipetteTargetId === param.id}
|
||||||
onPipetteToggle={() => onPipetteToggle?.(param.id)}
|
onPipetteToggle={() => onPipetteToggle?.(param.id)}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import { createAutoRunner } from '$lib/tools/auto-run';
|
import { createAutoRunner } from '$lib/tools/auto-run';
|
||||||
import { executeStep } from '$lib/tools/executor';
|
import { executeStep } from '$lib/tools/executor';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolDescription, toolTitle } from '$lib/i18n/tool-strings';
|
||||||
import ParamsCard from './tool/ParamsCard.svelte';
|
import ParamsCard from './tool/ParamsCard.svelte';
|
||||||
import ResultCard from './tool/ResultCard.svelte';
|
import ResultCard from './tool/ResultCard.svelte';
|
||||||
import SourceCard from './tool/SourceCard.svelte';
|
import SourceCard from './tool/SourceCard.svelte';
|
||||||
@@ -178,7 +179,7 @@
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
const rawMsg = e instanceof Error ? e.message : String(e);
|
const rawMsg = e instanceof Error ? e.message : String(e);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
t('toolPage.stepError', { n: i + 1, title: stepTool.title, msg: t(rawMsg) })
|
t('toolPage.stepError', { n: i + 1, title: toolTitle(stepTool), msg: t(rawMsg) })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!runner.isCurrent(token)) return;
|
if (!runner.isCurrent(token)) return;
|
||||||
@@ -255,8 +256,8 @@
|
|||||||
<svelte:window onpaste={handlePaste} />
|
<svelte:window onpaste={handlePaste} />
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h1>{tool.title}</h1>
|
<h1>{toolTitle(tool)}</h1>
|
||||||
<p class="description text-muted">{tool.description}</p>
|
<p class="description text-muted">{toolDescription(tool)}</p>
|
||||||
|
|
||||||
{#if errorText}
|
{#if errorText}
|
||||||
<div class="error-banner" role="alert">{errorText}</div>
|
<div class="error-banner" role="alert">{errorText}</div>
|
||||||
@@ -307,6 +308,7 @@
|
|||||||
<span class="edge-legend" aria-hidden="true">{t('toolPage.legendParams')}</span>
|
<span class="edge-legend" aria-hidden="true">{t('toolPage.legendParams')}</span>
|
||||||
</div>
|
</div>
|
||||||
<ParamsCard
|
<ParamsCard
|
||||||
|
tool={tool}
|
||||||
params={tool.params}
|
params={tool.params}
|
||||||
bind:values
|
bind:values
|
||||||
{pipetteTargetId}
|
{pipetteTargetId}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { outputOf, sanitizeParams, type ToolEntry } from '$lib/registry';
|
import { outputOf, sanitizeParams, type ToolEntry } from '$lib/registry';
|
||||||
import type { PixelImage } from '$lib/core/types';
|
import type { PixelImage } from '$lib/core/types';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolTitle } from '$lib/i18n/tool-strings';
|
||||||
import DownloadButton from '../DownloadButton.svelte';
|
import DownloadButton from '../DownloadButton.svelte';
|
||||||
import Button from '../ui/Button.svelte';
|
import Button from '../ui/Button.svelte';
|
||||||
import EmptyState from '../ui/EmptyState.svelte';
|
import EmptyState from '../ui/EmptyState.svelte';
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
{#if StepIcon}
|
{#if StepIcon}
|
||||||
<span class="step-icon" aria-hidden="true"><StepIcon size={14} strokeWidth={2} /></span>
|
<span class="step-icon" aria-hidden="true"><StepIcon size={14} strokeWidth={2} /></span>
|
||||||
{/if}
|
{/if}
|
||||||
{t('chain.stepLabel', { n: index + 1, title: tool.title })}
|
{t('chain.stepLabel', { n: index + 1, title: toolTitle(tool) })}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="remove"
|
class="remove"
|
||||||
@@ -99,7 +100,7 @@
|
|||||||
<div class="params-sep">
|
<div class="params-sep">
|
||||||
<span class="edge-legend" aria-hidden="true">{t('chain.paramsLegend')}</span>
|
<span class="edge-legend" aria-hidden="true">{t('chain.paramsLegend')}</span>
|
||||||
</div>
|
</div>
|
||||||
<ParamsCard params={tool.params} bind:values />
|
<ParamsCard tool={tool} params={tool.params} bind:values />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { isChainable, TOOLS } from '$lib/registry';
|
import { isChainable, TOOLS } from '$lib/registry';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolDescription, toolTitle } from '$lib/i18n/tool-strings';
|
||||||
import ToolCard from './ToolCard.svelte';
|
import ToolCard from './ToolCard.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -56,8 +57,8 @@
|
|||||||
if (s !== null && s > 0) {
|
if (s !== null && s > 0) {
|
||||||
found.push({
|
found.push({
|
||||||
id: tool.id,
|
id: tool.id,
|
||||||
title: tool.title,
|
title: toolTitle(tool),
|
||||||
description: tool.description,
|
description: toolDescription(tool),
|
||||||
popularity: tool.popularity ?? 50,
|
popularity: tool.popularity ?? 50,
|
||||||
score: s
|
score: s
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ParamForm from '../ParamForm.svelte';
|
import ParamForm from '../ParamForm.svelte';
|
||||||
import type { ParamDef } from '$lib/registry';
|
import type { ParamDef, ToolEntry } from '$lib/registry';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
tool: ToolEntry;
|
||||||
params: ParamDef[];
|
params: ParamDef[];
|
||||||
values: Record<string, any>;
|
values: Record<string, any>;
|
||||||
pipetteTargetId?: string | null;
|
pipetteTargetId?: string | null;
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
tool,
|
||||||
params,
|
params,
|
||||||
values = $bindable(),
|
values = $bindable(),
|
||||||
pipetteTargetId = null,
|
pipetteTargetId = null,
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
<div class="root">
|
<div class="root">
|
||||||
{#if params.length > 0 || hasMask}
|
{#if params.length > 0 || hasMask}
|
||||||
<ParamForm
|
<ParamForm
|
||||||
|
{tool}
|
||||||
{params}
|
{params}
|
||||||
bind:values
|
bind:values
|
||||||
{pipetteTargetId}
|
{pipetteTargetId}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
{:else if tool.resultType === 'text'}
|
{:else if tool.resultType === 'text'}
|
||||||
<div class="media">
|
<div class="media">
|
||||||
{#if textResult !== null}
|
{#if textResult !== null}
|
||||||
<TextResult text={textResult} filename={tool.id} />
|
<TextResult text={textResult} filename={tool.id} toolId={tool.id} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@@ -1,29 +1,35 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { downloadBlob } from '$lib/core/io';
|
import { downloadBlob } from '$lib/core/io';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { getMergedDict } from '$lib/i18n/locale.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
text: string;
|
text: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
|
toolId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { text, filename }: Props = $props();
|
let { text, filename, toolId }: Props = $props();
|
||||||
|
|
||||||
|
const shown = $derived(
|
||||||
|
toolId ? (getMergedDict().tools[toolId]?.results?.[text] ?? text) : text
|
||||||
|
);
|
||||||
|
|
||||||
let copied = $state(false);
|
let copied = $state(false);
|
||||||
|
|
||||||
async function copy() {
|
async function copy() {
|
||||||
await navigator.clipboard.writeText(text);
|
await navigator.clipboard.writeText(shown);
|
||||||
copied = true;
|
copied = true;
|
||||||
setTimeout(() => (copied = false), 1500);
|
setTimeout(() => (copied = false), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function download() {
|
function download() {
|
||||||
downloadBlob(new Blob([text], { type: 'text/plain' }), `${filename}.txt`);
|
downloadBlob(new Blob([shown], { type: 'text/plain' }), `${filename}.txt`);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="panel text-result">
|
<div class="panel text-result">
|
||||||
<textarea class="output" rows="10" readonly value={text} aria-label={t('textResult.outputAria')}></textarea>
|
<textarea class="output" rows="10" readonly value={shown} aria-label={t('textResult.outputAria')}></textarea>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button type="button" class="secondary" onclick={copy}>
|
<button type="button" class="secondary" onclick={copy}>
|
||||||
{copied ? t('textResult.copied') : t('textResult.copy')}
|
{copied ? t('textResult.copied') : t('textResult.copy')}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getTool } from '$lib/registry';
|
import { getTool } from '$lib/registry';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolTitle } from '$lib/i18n/tool-strings';
|
||||||
import ToolPage from '$lib/components/ToolPage.svelte';
|
import ToolPage from '$lib/components/ToolPage.svelte';
|
||||||
import ToolSearch from '$lib/components/search/ToolSearch.svelte';
|
import ToolSearch from '$lib/components/search/ToolSearch.svelte';
|
||||||
import Button from '$lib/components/ui/Button.svelte';
|
import Button from '$lib/components/ui/Button.svelte';
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
{@const restoreId = lastToolId}
|
{@const restoreId = lastToolId}
|
||||||
<div class="restore-row">
|
<div class="restore-row">
|
||||||
<Button variant="secondary" fullWidth onclick={() => openTool(restoreId, true)}>
|
<Button variant="secondary" fullWidth onclick={() => openTool(restoreId, true)}>
|
||||||
{t('home.restoreLast', { title: getTool(restoreId)?.title ?? '' })}
|
{t('home.restoreLast', { title: getTool(restoreId) ? toolTitle(getTool(restoreId)!) : '' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { CATEGORIES } from '$lib/categories';
|
import { CATEGORIES } from '$lib/categories';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolDescription, toolTitle } from '$lib/i18n/tool-strings';
|
||||||
import ToolCard from '$lib/components/search/ToolCard.svelte';
|
import ToolCard from '$lib/components/search/ToolCard.svelte';
|
||||||
import { TOOLS } from '$lib/registry';
|
import { TOOLS } from '$lib/registry';
|
||||||
</script>
|
</script>
|
||||||
@@ -23,8 +24,8 @@
|
|||||||
<div class="panel">
|
<div class="panel">
|
||||||
<ToolCard
|
<ToolCard
|
||||||
toolId={tool.id}
|
toolId={tool.id}
|
||||||
title={tool.title}
|
title={toolTitle(tool)}
|
||||||
description={tool.description}
|
description={toolDescription(tool)}
|
||||||
href="/tools/{tool.id}"
|
href="/tools/{tool.id}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import ToolPage from '$lib/components/ToolPage.svelte';
|
import ToolPage from '$lib/components/ToolPage.svelte';
|
||||||
import { getTool } from '$lib/registry';
|
import { getTool } from '$lib/registry';
|
||||||
import { t } from '$lib/i18n/t';
|
import { t } from '$lib/i18n/t';
|
||||||
|
import { toolDescription, toolTitle } from '$lib/i18n/tool-strings';
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
|
|
||||||
@@ -9,9 +10,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{tool?.title ?? t('toolPage.fallbackTitle')} — easy-png-tools</title>
|
<title>{tool ? toolTitle(tool) : t('toolPage.fallbackTitle')} — easy-png-tools</title>
|
||||||
{#if tool}
|
{#if tool}
|
||||||
<meta name="description" content={tool.description} />
|
<meta name="description" content={toolDescription(tool)} />
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user