Files
RUWIO/src/i18n/messages.ts
T
thandClaude Opus 4.7 31604052ca revert macro-clips button feature (keep markers + scripts)
The button authoring ended up too far from the intended model after
three correction passes. Pulling it out entirely so we can rebuild
from a clean spec. Markers, script tracks, script frames, the Action
editor, the Script DSL and the runtime for all of the above stay —
they work.

Removed:
- types: ButtonState, StateTransition, ButtonHitArea, ButtonClip,
  ButtonInstance, setButtonState/setButtonDisabled Action variants,
  Scene.buttonClips/buttonInstances
- store: activeButtonClip* getters, all add/remove/setButton* actions,
  seedDefaultButtonClip, enterButtonEdit/setActiveButtonState/
  exitButtonEdit, button-label resolution in actionRuntime
- useButtonRuntime composable, buttonBlend helper,
  ButtonInstanceDialog, sidebar Buttons section, Timeline button
  rendering + pointer handlers, CanvasStage button rendering +
  pointer state machine, exportPlayer button runtime + hit-testing
- DSL commands state/enable/disable and their parse errors
- 35 button-related tests + helpers; stale testing doc; stale design
  doc

Re-applied three uncommitted fixes that were unrelated to the button
work:
- clicking a marker no longer jumps the playhead (only drag / dblclick
  act on it)
- script tracks get a right-click context menu (rename + delete,
  color in the existing palette)
- onTracksPointerDown excludes .script-lane / .script-frame so
  clicks on empty lanes or on frame dots reach the frame-open path
  instead of being swallowed by box-select pointer capture

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:37:49 +02:00

396 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const en = {
app: {
undo: 'Undo (Ctrl+Z)',
redo: 'Redo (Ctrl+Shift+Z)',
jumpToStart: 'Jump to start',
pause: 'Pause (Space)',
play: 'Play (Space)',
stop: 'Stop',
recentProjects: 'Recent projects',
saveProject: 'Save project (browser storage)',
documentSettings: 'Document settings',
export: 'Export',
mainTimeline: 'Main timeline',
dragResize: 'Drag to resize timeline',
loadFailed: 'Failed to load project.',
savedToast: '"{name}" saved',
saveDialog: {
title: 'Save project',
message: 'What should the project be called?',
confirm: 'Save',
defaultName: 'Project {date}',
},
replaceDialog: {
title: 'Replace project?',
message:
'The current project will be replaced by the loaded file. Unsaved changes will be lost.',
confirm: 'Continue',
},
},
welcome: {
heading: 'Welcome to Animatr',
subheading: 'Recent projects',
loading: 'Loading…',
empty: 'No saved projects yet.',
layerCount: '{n} layers',
today: 'today {time}',
deleteTooltip: 'Delete project',
newProject: 'New project',
importFile: 'Import file…',
exportCurrent: 'Export current',
deleteDialog: {
title: 'Delete project?',
message: '"{name}" will be permanently removed from browser storage.',
confirm: 'Delete',
},
},
sidebar: {
addFile: 'Add SVG / image',
library: 'Library',
thumbnailsHide: 'Hide thumbnails',
thumbnailsShow: 'Show thumbnails',
imageLabel: 'Image',
addLayerTooltip: 'Insert as layer (or drag to stage)',
noImages: 'No images imported',
clips: 'Clips',
createClipTooltip: 'Create new clip',
clipLayerCount: '{n} layers',
renameTooltip: 'Rename',
deleteTooltip: 'Delete',
noClips: 'No clips',
shape: {
rect: 'Rect',
circle: 'Circle',
text: 'Text',
polygon: 'Polygon',
freeform: 'Freeform (click to draw, Enter to finish, Esc to cancel)',
freeformActive: 'Drawing… (Enter to finish, Esc to cancel)',
},
newTextDialog: {
title: 'New text object',
message: 'Text:',
default: 'Hello',
confirm: 'Insert',
fallback: 'Text',
},
newPolygonDialog: {
title: 'New polygon',
message: 'Number of points (3–24):',
confirm: 'Create',
},
newClipDialog: {
title: 'New clip',
message: 'Clip name:',
default: 'Clip',
confirm: 'Create',
},
renameClipDialog: {
title: 'Rename clip',
confirm: 'Apply',
},
deleteClipDialog: {
title: 'Delete clip?',
message: 'The clip and all placed instances will be removed.',
confirm: 'Delete',
},
},
properties: {
keyframeLabel: 'Keyframe',
interpolated: 'Interpolated',
removeKeyframe: 'Remove keyframe here',
deleteLayer: 'Delete layer',
noLayer: 'No layer selected.',
fill: 'Fill',
transparent: 'Transparent',
opacity: 'Opacity',
edgeBlur: 'Edge blur',
sections: {
transform: 'Transform',
text: 'Text',
polygon: 'Polygon',
appearance: 'Appearance',
},
polygonPoints: 'Points',
polygonPointsHint: 'Changing the point count rewrites all keyframes; new points are inserted at the midpoint of the last edge.',
polygonClosed: 'Closed path (fill)',
stroke: 'Stroke',
strokeWidth: 'Stroke width',
shadow: 'Shadow',
shadowBlur: 'Shadow blur',
shadowOpacity: 'Shadow opacity',
shadowAngle: 'Shadow angle',
shadowDistance: 'Shadow distance',
shadowColor: 'Shadow color',
mask: 'Mask',
maskUse: 'Use as mask',
maskMode: 'Mask mode',
maskPositive: 'Positive',
maskNegative: 'Negative',
maskHint: 'Masks everything below it in the same group.',
maskActive: 'Mask is active — affects layers below it in its group.',
maskNeedsGroup: 'Add this layer to a track group to activate masking. Right-click a track and choose "Add group".',
},
fullscreen: {
pause: 'Pause',
play: 'Play',
jumpToStart: 'Jump to start',
close: 'Close (Esc)',
},
timeline: {
colors: {
none: 'None',
red: 'Red',
orange: 'Orange',
yellow: 'Yellow',
green: 'Green',
cyan: 'Cyan',
blue: 'Blue',
purple: 'Purple',
pink: 'Pink',
gray: 'Gray',
},
noTracks: 'No tracks yet.',
addClipTrack: 'Add clip track',
addClipTrackTooltip: 'Add another clip track',
dropNewTrackHint: 'Drop a clip here to add a new track',
addGroup: 'Add group',
addGroupTooltip: 'Create a new track group',
scriptTrackName: 'Script track',
addScriptTrackTooltip: 'Create a new script track',
scriptFrameTooltip: 'Script frame — {n} action(s)',
addKeyframeTooltip: 'Add keyframe for the selected track at the playhead',
groupChildCount: '{n} tracks',
groupEmpty: 'Drop tracks here',
renameGroupDialog: {
title: 'Rename group',
confirm: 'Apply',
},
ungroup: 'Ungroup',
renameGroup: 'Rename group',
resizeTrackColumn: 'Drag to resize track name column',
clipTrackName: 'Clip track',
toggleTimeUnit: 'Toggle time unit',
snapOn: 'Snapping on (playhead & keyframes snap together)',
snapOff: 'Snapping off',
hideLocked: 'Hide locked tracks',
showLocked: 'Show locked tracks',
inPoint: 'In point — drag to set where playback and export start',
outPoint: 'Out point — drag to set where playback and export end',
renameMarkerTitle: 'Rename marker',
renameMarkerMessage: 'Pick a unique name — used as a jump target in scripts.',
renameMarkerConfirm: 'Rename',
renameMarkerCollision: 'A marker named "{name}" already exists.',
renameMarkerRetry: 'Try again',
stillFrameTooltip: 'Still frame {time} — holds until the next keyframe',
keyframeTooltip: 'Keyframe {time} — drag to move, right-click for options',
trimTooltip: '{name} · {duration}s{trims} · Drag edges to trim, double-click to open',
trimStart: 'Start -{value}s',
trimEnd: 'End -{value}s',
easing: 'Easing',
easingLinear: 'Linear',
easingEaseIn: 'Ease In',
easingEaseOut: 'Ease Out',
easingEaseInOut: 'Ease In-Out',
firstKfHint: 'First keyframe — easing has no effect',
holdDisabledHint: 'Still frame — easing disabled',
lastKfHint: 'Last keyframe — still frame has no effect',
stillFrame: 'Still frame',
duplicate: 'Duplicate',
delete: 'Delete',
color: 'Color',
lock: 'Lock',
unlock: 'Unlock',
deleteLayer: 'Delete layer',
deleteClipTrack: 'Delete clip track',
separate: 'Separate Position and Rotation',
rotation: 'Rotation',
position: 'Position',
removeInstanceDialog: {
title: 'Remove clip instance?',
message: 'Remove "{name}" at {time}s from the timeline.',
generic: 'Remove this clip instance from the timeline.',
confirm: 'Remove',
},
},
canvas: {
zoomIn: 'Zoom in',
zoomOut: 'Zoom out',
zoomOneToOne: 'Zoom 1:1',
fitToView: 'Fit to view',
cropOn: 'Show stage only (crop)',
cropOff: 'Show everything',
maskPreviewOn: 'Preview masks (render view)',
maskPreviewOff: 'Back to edit view',
vertexCorner: 'Corner',
vertexCurve: 'Curve (smooth)',
vertexSplitCurve: 'Split curve',
},
settings: {
title: 'Settings',
tab: {
document: 'Document',
timeline: 'Timeline',
clipart: 'Clipart',
theme: 'UI Theme',
},
bgVideoLabel: 'Video',
bgVideoNone: 'No background video',
bgVideoPickFile: 'Pick video file…',
bgVideoPickUrl: 'Set URL…',
bgVideoClear: 'Remove background video',
bgVideoLocalFile: 'Local video file',
bgVideoHint:
'The video plays behind all layers and tracks the playhead. For best results use MP4 (H.264). The source is stored with the project (data URL for local files) or referenced by URL. In the export the video is not embedded — the exported HTML references the same URL.',
bgVideoStageSizeTitle: 'Apply video dimensions?',
bgVideoStageSizeMessage:
'The video is {w}×{h}. Your canvas is currently {cw}×{ch}. Resize the canvas to match the video?',
bgVideoStageSizeConfirm: 'Resize canvas',
bgVideoStageSizeCancel: 'Keep current size',
bgVideoDurationTitle: 'Extend scene duration?',
bgVideoDurationMessage:
'The video is {d}s. Scene duration is {cd}s. Extend the scene to match the video length?',
bgVideoDurationConfirm: 'Extend duration',
bgVideoDurationCancel: 'Keep current duration',
bgVideoUrlTitle: 'Background video URL',
bgVideoUrlMessage: 'Paste the video URL (must be reachable by the browser):',
bgVideoUrlConfirm: 'Load',
canvas: 'Canvas',
width: 'Width',
height: 'Height',
background: 'Background',
duration: 'Duration (s)',
fps: 'FPS',
timelineHint: 'Timeline length sets the ruler scale. Playback stops at the last keyframe.',
themeHint: 'Saved in the browser and reused on next open.',
themeDark: 'Dark',
themeLight: 'Light',
done: 'Done',
},
export: {
title: 'Export',
runtimeBadge: '1× per page',
runtimeDesc: 'Engine — include once; all scenes on the page share the runtime',
sceneBadge: 'Scene',
sceneDesc: 'Scene data only — requires the runtime to be loaded',
exampleTitle: 'Example HTML',
exampleDesc: 'Standalone HTML — just open it in a browser',
mp4Badge: 'Server · Frame-accurate',
mp4Desc: 'H.264, any resolution — requires render server',
webmBadge: 'Browser · Realtime',
webmDesc: 'No server — recorded in real time',
webmNotSupported: 'Browser does not support MediaRecorder',
cancel: 'Cancel',
failed: 'Export failed',
back: 'Back',
labelWebm: 'Rendering WebM (browser, realtime)…',
labelMp4: 'Rendering MP4 (server)…',
},
tests: {
running: 'Tests running',
title: 'Test Runner',
runAgain: 'Run again',
close: 'Close',
copyTooltip: 'Copy report to clipboard',
copiedTooltip: 'Report copied',
copiedBanner: 'Error report copied to clipboard.',
copyFailedBanner: 'Copy failed — use the clipboard icon to trigger manually.',
emptyState: 'No results — click "Run again" or press {shortcut}.',
testsCountLabel: '{n} tests',
passedLabel: '{n} passed',
failedLabel: '{n} failed',
},
clipart: {
title: 'Clipart library',
open: 'Open clipart library',
close: 'Close clipart library',
refresh: 'Reload folder',
empty: 'Choose a folder in settings to populate the library.',
noFiles: 'No image files in this folder.',
loading: 'Loading…',
unsupported: 'Your browser does not support folder access. Try Chrome or Edge.',
chooseFolder: 'Choose folder…',
clearFolder: 'Clear',
folderLabel: 'Folder',
noFolder: 'No folder selected',
settingsHint:
'Point to a local folder with your SVG/PNG/JPG clipart. The app remembers the folder; permissions may be re-asked after browser restart.',
},
dialog: {
confirm: 'Confirm',
input: 'Input',
ok: 'OK',
cancel: 'Cancel',
close: 'Close',
},
about: {
openTooltip: 'About Animatr',
title: 'About {name}',
tagline: 'A timeline-based animation editor that runs in your browser.',
versionLabel: 'Version',
buildLabel: 'Build',
close: 'Close',
shortcutsHeading: 'Shortcuts',
shortcut: {
undo: 'Ctrl+Z',
redo: 'Ctrl+Shift+Z',
playPause: 'Space',
fullscreen: 'Shift+Space',
tests: 'Ctrl+Shift+Alt+T',
panCanvas: 'Middle-click / Ctrl+Drag',
},
shortcutLabel: {
undo: 'Undo',
redo: 'Redo',
playPause: 'Play / Pause',
fullscreen: 'Fullscreen preview',
tests: 'Open test runner',
panCanvas: 'Pan canvas',
},
},
actions: {
empty: 'No actions yet. Add one below.',
add: 'Add action',
remove: 'Remove',
moveUp: 'Move up',
moveDown: 'Move down',
noMarkers: 'No markers defined',
type: {
play: 'Play',
pause: 'Pause',
rewindToLoop: 'Rewind to loop start',
jumpTo: 'Jump to time',
jumpToFrame: 'Jump to frame',
jumpToMarker: 'Jump to marker',
script: 'Run script',
},
param: {
time: 'Seconds',
frame: 'Frame',
marker: 'Marker',
source: 'Script source',
},
},
scriptFrameDialog: {
title: 'Script frame',
time: 'Time (s)',
label: 'Label (optional)',
labelPlaceholder: 'e.g. intro-end',
remove: 'Delete frame',
done: 'Done',
},
} as const
export type Messages = typeof en