- {@render children()}
-
+ {#key page.url.pathname}
+
+ {@render children()}
+
+ {/key}
diff --git a/frontend/src/lib/components/JinjaEditor.svelte b/frontend/src/lib/components/JinjaEditor.svelte index b87ea4c..3031cc3 100644 --- a/frontend/src/lib/components/JinjaEditor.svelte +++ b/frontend/src/lib/components/JinjaEditor.svelte @@ -1,22 +1,44 @@
diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 0563436..e5fe806 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -266,8 +266,48 @@ "telegramSettings": "Telegram", "videoWarning": "Video warning", "preview": "Preview", + "variables": "Variables", + "assetFields": "Asset fields (in {% for asset in added_assets %})", "confirmDelete": "Delete this template config?" }, + "templateVars": { + "message_assets_added": { "description": "Notification when new assets are added to an album" }, + "message_assets_removed": { "description": "Notification when assets are removed from an album" }, + "message_album_renamed": { "description": "Notification when an album is renamed" }, + "message_album_deleted": { "description": "Notification when an album is deleted" }, + "periodic_summary_message": { "description": "Periodic album summary with stats" }, + "scheduled_assets_message": { "description": "Scheduled asset picks from albums" }, + "memory_mode_message": { "description": "\"On This Day\" memories from past years" }, + "album_name": "Album name", + "album_url": "Public share URL (if available)", + "added_count": "Number of assets added", + "removed_count": "Number of assets removed", + "change_type": "Type of change", + "people": "Detected people names (use {{ people | join(', ') }})", + "added_assets": "List of added asset objects (use {% for asset in added_assets %})", + "removed_assets": "List of removed asset IDs", + "shared": "Whether album is shared (true/false)", + "video_warning": "Video size warning text", + "old_name": "Previous album name", + "new_name": "New album name", + "albums": "List of album objects (use {% for album in albums %})", + "assets": "List of asset objects (use {% for asset in assets %})", + "date": "Current date/time", + "asset_filename": "Original filename", + "asset_type": "IMAGE or VIDEO", + "asset_created_at": "Creation date/time (ISO 8601)", + "asset_owner": "Owner display name", + "asset_description": "User or EXIF description", + "asset_url": "Public viewer URL", + "asset_download_url": "Direct download URL", + "asset_photo_url": "Preview image URL (images only)", + "asset_playback_url": "Video playback URL (videos only)", + "asset_is_favorite": "Whether asset is favorited", + "asset_rating": "Star rating (1-5 or null)", + "asset_city": "City name", + "asset_state": "State/region name", + "asset_country": "Country name" + }, "hints": { "periodicSummary": "Sends a scheduled summary of all tracked albums at specified times. Great for daily/weekly digests.", "scheduledAssets": "Sends random or selected photos from tracked albums on a schedule. Like a daily photo pick.", @@ -318,6 +358,8 @@ "newPassword": "New password", "passwordChanged": "Password changed successfully", "expand": "Expand", - "collapse": "Collapse" + "collapse": "Collapse", + "syntaxError": "Syntax error", + "line": "line" } } diff --git a/frontend/src/lib/i18n/index.svelte.ts b/frontend/src/lib/i18n/index.svelte.ts index 918209b..4c208b4 100644 --- a/frontend/src/lib/i18n/index.svelte.ts +++ b/frontend/src/lib/i18n/index.svelte.ts @@ -45,9 +45,10 @@ export function initLocale() { * Falls back to English if key not found in current locale. * Reactive: re-evaluates when currentLocale changes. */ -export function t(key: string): string { +export function t(key: string, fallback?: string): string { return resolve(translations[currentLocale], key) ?? resolve(translations.en, key) + ?? fallback ?? key; } diff --git a/frontend/src/lib/i18n/ru.json b/frontend/src/lib/i18n/ru.json index 6c203f5..b088ca2 100644 --- a/frontend/src/lib/i18n/ru.json +++ b/frontend/src/lib/i18n/ru.json @@ -266,8 +266,48 @@ "telegramSettings": "Telegram", "videoWarning": "Предупреждение о видео", "preview": "Предпросмотр", + "variables": "Переменные", + "assetFields": "Поля файла (в {% for asset in added_assets %})", "confirmDelete": "Удалить эту конфигурацию шаблона?" }, + "templateVars": { + "message_assets_added": { "description": "Уведомление о добавлении файлов в альбом" }, + "message_assets_removed": { "description": "Уведомление об удалении файлов из альбома" }, + "message_album_renamed": { "description": "Уведомление о переименовании альбома" }, + "message_album_deleted": { "description": "Уведомление об удалении альбома" }, + "periodic_summary_message": { "description": "Периодическая сводка альбомов со статистикой" }, + "scheduled_assets_message": { "description": "Запланированная подборка фото из альбомов" }, + "memory_mode_message": { "description": "«В этот день» — фото из прошлых лет" }, + "album_name": "Название альбома", + "album_url": "Публичная ссылка (если есть)", + "added_count": "Количество добавленных файлов", + "removed_count": "Количество удалённых файлов", + "change_type": "Тип изменения", + "people": "Обнаруженные люди ({{ people | join(', ') }})", + "added_assets": "Список добавленных файлов ({% for asset in added_assets %})", + "removed_assets": "Список ID удалённых файлов", + "shared": "Общий альбом (true/false)", + "video_warning": "Предупреждение о размере видео", + "old_name": "Прежнее название альбома", + "new_name": "Новое название альбома", + "albums": "Список альбомов ({% for album in albums %})", + "assets": "Список файлов ({% for asset in assets %})", + "date": "Текущая дата/время", + "asset_filename": "Имя файла", + "asset_type": "IMAGE или VIDEO", + "asset_created_at": "Дата создания (ISO 8601)", + "asset_owner": "Имя владельца", + "asset_description": "Описание (EXIF или пользовательское)", + "asset_url": "Ссылка для просмотра", + "asset_download_url": "Ссылка для скачивания", + "asset_photo_url": "URL превью (только фото)", + "asset_playback_url": "URL видео (только видео)", + "asset_is_favorite": "В избранном", + "asset_rating": "Рейтинг (1-5 или null)", + "asset_city": "Город", + "asset_state": "Регион", + "asset_country": "Страна" + }, "hints": { "periodicSummary": "Отправляет плановую сводку по всем отслеживаемым альбомам в указанное время. Подходит для ежедневных/еженедельных дайджестов.", "scheduledAssets": "Отправляет случайные или выбранные фото из альбомов по расписанию. Как ежедневная подборка фото.", @@ -318,6 +358,8 @@ "newPassword": "Новый пароль", "passwordChanged": "Пароль успешно изменён", "expand": "Развернуть", - "collapse": "Свернуть" + "collapse": "Свернуть", + "syntaxError": "Ошибка синтаксиса", + "line": "строка" } } diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 4646158..8e53e8a 100644 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -3,6 +3,7 @@ import { page } from '$app/state'; import { goto } from '$app/navigation'; import { onMount } from 'svelte'; + import { fade } from 'svelte/transition'; import { api } from '$lib/api'; import { getAuth, loadUser, logout } from '$lib/auth.svelte'; import { t, initLocale, getLocale, setLocale, type Locale } from '$lib/i18n'; @@ -196,9 +197,11 @@Syntax error: {slotErrors[slot.key]}
+{t('common.syntaxError')}: {slotErrors[slot.key]}{slotErrorLines[slot.key] ? ` (${t('common.line')} ${slotErrorLines[slot.key]})` : ''}
{/if} {#if slotPreview[slot.key]}{varsRef[showVarsFor].description}
+{t(`templateVars.${showVarsFor}.description`, varsRef[showVarsFor].description)}
Variables:
+{t('templateConfig.variables')}:
{#each Object.entries(varsRef[showVarsFor].variables || {}) as [name, desc]}{'{{ ' + name + ' }}'}
- {desc}
+ {t(`templateVars.${name}`, desc as string)}
Asset fields (in {'{'}% for asset in added_assets %{'}'}):
+{t('templateConfig.assetFields')}:
{#each Object.entries(varsRef[showVarsFor].asset_fields || {}) as [name, desc]}{'{{ asset.' + name + ' }}'}
- {desc}
+ {t(`templateVars.asset_${name}`, desc as string)}